Skip to content

feat: redesign runner memory tiers#173

Open
i-am-thor[bot] wants to merge 6 commits into
mainfrom
feat/memory-tiers
Open

feat: redesign runner memory tiers#173
i-am-thor[bot] wants to merge 6 commits into
mainfrom
feat/memory-tiers

Conversation

@i-am-thor
Copy link
Copy Markdown
Contributor

@i-am-thor i-am-thor Bot commented May 31, 2026

Summary

  • replace runner-injected per-repo memory with global, channel, and person tiers
  • document the new memory model and read/write policy in repo docs and build prompt guidance
  • add runner coverage for Slack channel memory and GitHub/Slack user-to-person memory resolution

Testing

  • pnpm exec vitest run packages/runner/src/trigger.test.ts packages/runner/src/memory-progress.test.ts
  • pnpm --filter @thor/runner typecheck

AI-generated — verify before acting. View Thor context

Co-authored-by: Son Dao <son.dao@katalon.com>
Comment thread docker/opencode/config/agents/build.md Outdated
- Additional memory files: `/workspace/memory/` and `/workspace/memory/<repo>/` — store one topic per file, list and grep as needed.
- Global memory: `/workspace/memory/README.md` — injected into every new session. Use only for rare cross-cutting Thor context, critical durable corrections, and workspace-wide operating notes. Keep short.
- Channel memory: `/workspace/memory/channels/<channel-id>.md` — injected into new Slack thread sessions when the correlation key is `slack:thread:<channel>/<ts>`. Use for durable channel/team preferences, recurring workflows, and channel-specific norms.
- Person memory: `/workspace/memory/people/<person-slug>.md` — injected into new sessions when the triggering actor resolves through `/workspace/config/thor.json` `users[]`. The slug prefers email local-part (for example `Son.Dao@example.com` → `people/son.dao.md`), else GitHub login, else sanitized name. Use for durable user preferences and identity context.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use john doe / acme.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the examples to use john.doe / acme in 3794801.


AI-generated — verify before acting. View Thor context

Comment thread docker/opencode/config/agents/build.md Outdated
- Global memory: `/workspace/memory/README.md` — injected into every new session. Use only for rare cross-cutting Thor context, critical durable corrections, and workspace-wide operating notes. Keep short.
- Channel memory: `/workspace/memory/channels/<channel-id>.md` — injected into new Slack thread sessions when the correlation key is `slack:thread:<channel>/<ts>`. Use for durable channel/team preferences, recurring workflows, and channel-specific norms.
- Person memory: `/workspace/memory/people/<person-slug>.md` — injected into new sessions when the triggering actor resolves through `/workspace/config/thor.json` `users[]`. The slug prefers email local-part (for example `Son.Dao@example.com` → `people/son.dao.md`), else GitHub login, else sanitized name. Use for durable user preferences and identity context.
- Repo-scoped context: not runner-injected memory. Use repo-local `AGENTS.md`, `CLAUDE.md`, and in-repo docs for repo/product facts, codebase conventions, runbooks, and anything humans should also see. Do not create or rely on `/workspace/memory/<repo>/README.md` for new repo context.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Never mention /README.md to avoid confusing LLM.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the <repo>/README.md mention from the prompt/docs in 3794801.


AI-generated — verify before acting. View Thor context

Comment thread docker/opencode/config/agents/build.md Outdated
- Repo-scoped context: not runner-injected memory. Use repo-local `AGENTS.md`, `CLAUDE.md`, and in-repo docs for repo/product facts, codebase conventions, runbooks, and anything humans should also see. Do not create or rely on `/workspace/memory/<repo>/README.md` for new repo context.

**Reading:** at the start of non-trivial sessions, check for relevant memory files by listing and grepping `/workspace/memory/`. For recovering prior context (Slack threads, past decisions, earlier investigations), search `/workspace/worklog/` first — it is faster and more complete than scanning Slack history. When a prompt says "Previous session was lost" and points at a worklog note, read that note directly as the continuity artifact.
**Reading:** the runner injects global/channel/person memory on new sessions only. For additional Thor-only context, check relevant files under `/workspace/memory/`. For recovering prior context (Slack threads, past decisions, earlier investigations), search `/workspace/worklog/` first — it is faster and more complete than scanning Slack history. When a prompt says "Previous session was lost" and points at a worklog note, read that note directly as the continuity artifact.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LLM should search /workspace/runs/ as it has more useful information density than worklog. Too much noise there. For something non-trivial, not worth adding a run directory -> probably not worth being recalled anyway.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the reading guidance to prefer /workspace/runs/ for non-trivial recurring work, and kept /workspace/worklog/ only for continuity/audit use in 3794801.


AI-generated — verify before acting. View Thor context

Comment thread docs/feat/memory.md Outdated
| Person | `/workspace/memory/people/<person-slug>.md` | Yes, when the trigger actor resolves through `/workspace/config/thor.json` | Durable user preferences, identity context, preferred follow-up style, stable ownership hints. |
| Repo context | Repo-local `AGENTS.md`, `CLAUDE.md`, and docs | Delegated to OpenCode/repo files | Product facts, codebase conventions, runbooks, and anything humans should review in git. |

The runner no longer injects `/workspace/memory/<repo>/README.md`. Keep
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not useful. Just not mention /README.md at all because after this PR, we will drop that feature completely.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed that <repo>/README.md mention from docs/feat/memory.md in 3794801.


AI-generated — verify before acting. View Thor context

Comment thread docs/feat/memory.md Outdated
Person memory filenames are deterministic:

1. email local-part from `users[].email`, lowercased and sanitized (for example
`Son.Dao@example.com` → `people/son.dao.md`)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use john doe / acme.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the examples to john.doe@example.com / acme@example.com in 3794801.


AI-generated — verify before acting. View Thor context

Comment thread packages/runner/src/index.ts Outdated
Comment on lines +161 to +177
function sanitizePersonSlugPart(value: string): string {
return value
.trim()
.toLowerCase()
.replace(/[^a-z0-9._-]+/g, "-")
.replace(/^[._-]+|[._-]+$/g, "")
.replace(/[-_.]{2,}/g, (match) => match[0] ?? "-");
}

function personSlug(user: UserRecord): string | undefined {
const emailLocalPart = user.email.split("@")[0];
return (
sanitizePersonSlugPart(emailLocalPart ?? "") ||
sanitizePersonSlugPart(user.github ?? "") ||
sanitizePersonSlugPart(user.name)
);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keep this simple. email should be safe for file path anyway. Also: user email only, skip person memory logic if no email.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simplified the logic to use only the lowercased email local-part from the resolved user record. If the actor does not resolve through users[], person memory is skipped. Pushed in 3794801.


AI-generated — verify before acting. View Thor context

Co-authored-by: Son Dao <son.dao@katalon.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR redesigns the runner’s injected “durable memory” model by replacing per-repo memory injection with three tiers (global, Slack channel, and person), and updates both runner behavior and documentation to match.

Changes:

  • Update runner bootstrap prompt injection to read global memory, optional Slack channel memory (by slack:thread:<channel>/<ts> correlationKey), and optional person memory (by resolved triggering actor).
  • Add/expand runner tests covering channel memory injection and Slack/GitHub actor → person memory resolution.
  • Document the new memory tiers plus read/write policy across repo docs and OpenCode build prompt guidance.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
README.md Updates ops guidance to point to the new memory tiers and clarifies repo context belongs in-repo.
packages/runner/src/trigger.test.ts Expands test coverage to assert global/channel/person memory injection behavior and actor resolution paths.
packages/runner/src/index.ts Implements the new memory-tier bootstrap behavior and triggering-user resolution changes.
docs/feat/memory.md Adds a concise spec of memory tiers and runner read/write policy.
docs/feat/agent-protocols.md Links protocols doc to the new memory model document.
docker/opencode/config/agents/build.md Updates prompt guidance to reflect global/channel/person memory and repo-local context policy.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +155 to +158
const slackThread = parseSlackThreadCorrelationKey(correlationKey);
if (!slackThread) return undefined;
const path = `${memoryDir}/channels/${slackThread.channelId}.md`;
return { channelId: slackThread.channelId, path, content: readMemoryFile(path) };
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noted. I confirmed with the original requester and we are intentionally not adding another code safeguard here because the Slack channel id comes from Thor's signed Slack webhook intake path rather than arbitrary end-user text. I recorded that decision in the task plan/decision log.


AI-generated — verify before acting. View Thor context

Co-authored-by: Son Dao <son.dao@katalon.com>
@daohoangson
Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

Copy link
Copy Markdown
Contributor

Copilot AI commented May 31, 2026

@copilot resolve the merge conflicts in this pull request

Resolved and committed the merge conflicts in e03d081.

Copilot AI requested a review from daohoangson May 31, 2026 15:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants