feat(foreman): multi-repo — read/write specs in any configured repo, not just cwd #254
Labels
No labels
area:agents
area:dashboard
area:database
area:design
area:design-review
area:flows
area:infra
area:meta
area:security
area:sessions
area:webhook
area:workdir
security
type:bug
type:chore
type:meta
type:user-story
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Depends on
#253 design(planner): Penpot mockup — foreman multi-repo repo picker
charles/claude-hooks
Reference
charles/claude-hooks#254
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
User story
As an operator of a multi-repo claude-hooks deployment, I want the foreman to be able to read specs, write specs, and
@file-mention files from any repo inconfig.repos— not just the checkout it runs in — so I can draft and break down work forcharles/proxmox-iac(or any other watched repo) from the same Planner UI.Today
process.cwd()scopes every file operation to the claude-hooks source tree. The service already watches multiple repos via the webhook layer; the foreman is the only surface still hardcoded to one.Dependencies
Acceptance criteria
Session state
foreman_sessionstable (or wherever the SQLite schema lives — likelyapps/server/src/foreman.ts) gains arepo TEXT NOT NULLcolumn. Migration fills existing rows with the first entry fromcfg.repos(orcharles/claude-hooksas a sentinel).cfg.repos[0]unless the POST /foreman/chat body overrides it. Overrides must be validated againstcfg.repos— 400 on unknown repo.Endpoints
GET /foreman/files?repo=owner/name— whenrepoequals the cwd repo, scan the local filesystem as today. Otherwise use the Forgejo content API (GET /repos/{owner}/{repo}/contents/specs) with the foreman's token. 403 when!cfg.repos.includes(repo).GET /foreman/file-content?repo=owner/name&path=specs/foo.md— same split (local fs vs. Forgejo content API). Returns{ path, content, sha }.POST /foreman/savegains arepofield — when it's the cwd repo, write to disk + commit via git (current behavior). Otherwise go through Forgejocreate_file/update_filewith the foreman identity. Commit message convention:spec(foreman): update specs/<name>.md via Planner.POST /foreman/chat— acceptsrepoin the body; stores on session. Each turn's prompt is augmented with a line likeActive repo: <owner>/<name>so the foreman knows the context.Tool allowlist / canUseTool rails
foreman.ts::buildForemanSdkOptionscanUseToolhook: block anymcp__forgejo__*call whoseowner+repoargs don't match the active session's repo. Keeps a compromised prompt from leaking into other repos the foreman's token can reach.UI
@fileautocomplete scopes to the active repo.Verification
apps/server/src/foreman.test.ts— POST /foreman/chat withrepo: "charles/proxmox-iac", assert the stored session row carries that repo, assert the Forgejo content API is called (mocked) rather than local fs.cfg.repos-mismatchedrepo.charles/proxmox-iac,@an existing spec from that repo, confirm it inlines. Save a new spec via the editor; verify the file landed in Forgejo (not on disk).Out of scope
/breakdowndispatch — already works;/breakdowntakesrepoas a parameter and validates againstcfg.repos.References
apps/server/src/foreman.ts— file endpoints + session handlers.apps/server/src/main.ts::handleForemanConfig— already returnsreposon /foreman/config; UI just needs to wire it.apps/server/src/forgejo-api.ts— containsgetFileContent, may need acreateFile/updateFilewrapper if not already present.apps/web/src/lib/foreman.ts— client-side fetch helpers to extend with therepoparam.🤖 Auto-assigned to boss (heuristic: area:agents → boss (architecture-touching)). Reply
/unassignto reroute.