Repository navigation
feat(dir-add): scaffold agent.yaml + body-only AGENTS.md (wish dir-sync-frontmatter-refresh group 5) - #1198
Conversation
…nc-frontmatter-refresh group 5)
Wave 3 / Group 5. `genie dir add <name>` now scaffolds BOTH files on
disk — `agent.yaml` (runtime config from CLI flags) and a
frontmatter-less `AGENTS.md` (pure prompt content from line 1) — then
syncs the DB row from the yaml via the same single-agent path as
`dir edit` from Group 4.
Behavior:
- `mkdirSync(agentDir, { recursive: true })` creates the folder.
- `AGENTS.md` is scaffolded from an inline template that starts with
`# Agent: <name>` — no `---` fence. The template includes a
`<mission>TBD</mission>` placeholder to prompt the user.
- `writeAgentYaml(join(dir, 'agent.yaml'), config)` writes the config
atomically via the lockfile from Group 1.
- `syncSingleAgentByName(ws.root, name)` upserts the DB row via the
G3 sync path so `dir add` is read-after-write consistent.
- If not in a workspace: fall back to `directory.add` so the row
still registers; print a warning suggesting `genie dir sync`.
Tests (`src/term-commands/dir-add.test.ts` — new, 6 cases):
- creates both `agent.yaml` and `AGENTS.md`
- `AGENTS.md.slice(0, 3) !== '---'` (no frontmatter fence)
- `agent.yaml` parses cleanly; `--model` value lands inside
- DB directory entry has matching `model`
- `--permission-preset` + `--allow` flatten into `permissions.*`
nested yaml + DB
- re-writing agent.yaml and re-syncing produces the new state in DB
(idempotency of the write-then-sync cycle)
No direct `sql\`INSERT INTO agent_templates\`` calls in the add
handler path anymore; the DB projection flows from the yaml.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Code Review
This pull request updates the genie dir add command to scaffold both an agent.yaml configuration file and a frontmatter-less AGENTS.md file, followed by a database sync. It also adds comprehensive integration tests for this new behavior. Review feedback identifies a risk of overwriting existing agent configurations without a prior check and a bug in the workspace detection logic that fails to correctly register agents using custom directory paths.
| // canonical source of every runtime-consumed field; AGENTS.md holds pure | ||
| // prompt content from line 1. | ||
|
|
||
| const promptMode = validatePromptMode(options.promptMode); |
There was a problem hiding this comment.
The handleDirAdd function should check if an agent with the same name already exists in the directory before scaffolding files. Currently, it proceeds to create directories and overwrite agent.yaml even if the agent is already registered in the database, which can lead to accidental loss of existing configuration.
| const promptMode = validatePromptMode(options.promptMode); | |
| const existing = await directory.resolve(name); | |
| if (existing && !existing.builtin) { | |
| throw new Error("Agent " + name + " already exists. Use 'genie dir edit' to update or 'genie dir rm' first."); | |
| } | |
| const promptMode = validatePromptMode(options.promptMode); |
| const ws = findWorkspace(); | ||
| if (ws) { | ||
| await syncSingleAgentByName(ws.root, name); | ||
| } else { | ||
| // Not in a workspace — register a stub in the directory table so the | ||
| // agent is reachable even before the user runs `genie init`. | ||
| await directory.add( | ||
| { | ||
| name, | ||
| dir: resolvedDir, | ||
| repo: options.repo ? resolvePath(options.repo) : undefined, | ||
| promptMode, | ||
| model: options.model, | ||
| roles: normalizeRoles(options.roles), | ||
| ...(permissions && { permissions }), | ||
| ...(sdk && { sdk }), | ||
| }, | ||
| { global: options.global }, | ||
| ); | ||
| console.warn('Not in a genie workspace — directory row created; run `genie dir sync` in a workspace to re-sync.'); | ||
| } |
There was a problem hiding this comment.
There is a bug in the workspace detection logic: syncSingleAgentByName only works for agents located in the standard {workspace}/agents/{name} directory. If a user provides a custom path via --dir, syncSingleAgentByName will return 'not-found' and the agent will not be registered in the database, even though the CLI reports success. The logic should fall back to directory.add for non-standard paths to ensure the agent is correctly registered in the database.
const ws = findWorkspace();
const isStandardPath = ws && resolvedDir === resolvePath(join(ws.root, 'agents', name));
if (isStandardPath) {
await syncSingleAgentByName(ws.root, name);
} else {
// Not in a workspace or using a custom directory — register via directory.add
// to ensure the DB row exists with the correct path.
await directory.add(
{
name,
dir: resolvedDir,
repo: options.repo ? resolvePath(options.repo) : undefined,
promptMode,
model: options.model,
roles: normalizeRoles(options.roles),
...(permissions && { permissions }),
...(sdk && { sdk }),
},
{ global: options.global },
);
if (!ws) {
console.warn("Not in a genie workspace — directory row created; run genie dir sync in a workspace to re-sync.");
}
}There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b523f293e2
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| const scope = options.global ? 'global' : 'project'; | ||
| console.log(`Agent "${entry.name}" registered (${scope}).`); | ||
| printEntry(entry); | ||
| console.log(`Agent "${name}" registered (${scope}).`); |
There was a problem hiding this comment.
Check sync outcome before declaring registration success
This path always prints Agent "..." registered even when the workspace sync does not register anything. In workspace mode, syncSingleAgentByName(ws.root, name) can return not-found (for example when --dir is not exactly {workspace}/agents/{name}), but the command still emits a success message and continues, leaving no corresponding directory row. Please gate the success output on the sync action (or fall back to directory.add) so users do not get false-positive registration results.
Useful? React with 👍 / 👎.
| // Propagate to the DB via the same single-agent sync path used by `dir edit`. | ||
| const ws = findWorkspace(); | ||
| if (ws) { | ||
| await syncSingleAgentByName(ws.root, name); |
There was a problem hiding this comment.
Preserve --repo when syncing newly added workspace agents
In the workspace branch, registration goes through syncSingleAgentByName instead of directory.add, which means the persisted repo comes from sync discovery (git remote/agent dir) rather than the CLI --repo value written into config. As a result, genie dir add <name> --repo <path> no longer reliably stores the requested repo for workspace users, which is a behavior regression from the previous direct directory.add flow.
Useful? React with 👍 / 👎.
Wave 3 / Group 5 of wish `dir-sync-frontmatter-refresh`. Depends on Groups 1-4 (all on dev).
Behavior change
`genie dir add ` now scaffolds BOTH files on disk:
Then triggers `syncSingleAgentByName` (from G3/G4) so the DB row materializes from the yaml. Read-after-write consistent.
Code
`src/term-commands/dir.ts` — rewrote `handleDirAdd`:
Tests
`src/term-commands/dir-add.test.ts` (new, 6 cases):
Test plan
🤖 Generated with Claude Code