Skip to content

feat: make CLI agent-friendly (--yes, --json, --help examples, --dry-run)#12

Merged
ryanmcmillan merged 2 commits intomainfrom
feature/agent-friendly-cli
Mar 25, 2026
Merged

feat: make CLI agent-friendly (--yes, --json, --help examples, --dry-run)#12
ryanmcmillan merged 2 commits intomainfrom
feature/agent-friendly-cli

Conversation

@ryanmcmillan
Copy link
Copy Markdown
Member

Summary

Makes the Delega CLI fully scriptable and agent-friendly, inspired by Eric Zakariasson's "Building CLIs for Agents".

  • --yes / -y flag on tasks delete and agents rotate to skip interactive confirm() prompts — previously a blocker for non-interactive/agent usage
  • --json flag added to tasks complete, tasks delete, tasks delegate, and agents rotate — these commands previously only printed human-readable text
  • Usage examples added to every subcommand's --help output via addHelpText("after", ...) — agents can pattern-match off real invocations
  • --dry-run flag on destructive commands (tasks delete, agents rotate, reset) — preview what would happen without executing

All existing interactive behavior is preserved as the default. No breaking changes.

Test plan

  • npm run build passes (verified locally)
  • delega tasks delete <id> --yes skips confirmation
  • delega agents rotate <id> --yes skips confirmation
  • delega tasks delete <id> still prompts interactively (no regression)
  • delega tasks complete <id> --json returns JSON
  • delega tasks delete <id> --json --yes returns {"id":"...","deleted":true}
  • delega tasks delegate <tid> <aid> --content "x" --json returns subtask JSON
  • delega agents rotate <id> --json --yes returns {"id":"...","api_key":"..."}
  • delega tasks list --help shows examples section
  • delega tasks delete --dry-run <id> previews without deleting
  • delega agents rotate --dry-run <id> previews without rotating
  • delega reset --dry-run previews without cleaning

🤖 Generated with Claude Code

…run)

Add features to make the CLI scriptable and agent-friendly:

- Add --yes/-y flag to `tasks delete` and `agents rotate` to skip
  interactive confirmation prompts (blocker for non-interactive use)
- Add --json flag to `tasks complete`, `tasks delete`, `tasks delegate`,
  and `agents rotate` (previously human-readable text only)
- Add usage examples via addHelpText("after") to every subcommand
- Add --dry-run flag to `tasks delete`, `agents rotate`, and `reset`
  for previewing destructive operations without executing them

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Mar 25, 2026

Greptile Summary

This PR adds agent/scripting-friendly flags (--yes, --json, --dry-run) to destructive and output-only commands, plus --help examples across every subcommand. The changes are well-scoped and non-breaking — all interactive defaults are preserved.

Key changes:

  • tasks delete and agents rotate gain --yes (skip confirmation) and --dry-run (preview without side effects)
  • tasks complete, tasks delete, tasks delegate, and agents rotate gain --json for machine-readable output
  • reset gains --dry-run but no --json flag, making it slightly inconsistent with the other two destructive commands
  • --dry-run on tasks delete makes a real GET API call to retrieve the task content for the preview, while agents rotate --dry-run makes no network request — a subtle inconsistency worth aligning
  • All commands receive addHelpText("after", ...) examples, which is a solid UX pattern for agent discoverability

Confidence Score: 4/5

  • Safe to merge — no breaking changes and all existing interactive flows are preserved; a few minor inconsistencies remain.
  • The implementation is clean and achieves its stated goals. The only non-trivial concerns are: (1) reset --dry-run lacks --json support unlike the other destructive commands, and (2) tasks delete --dry-run makes a live API call while agents rotate --dry-run does not, creating inconsistent behavior. Neither is a blocker, but the inconsistency in dry-run semantics is worth a targeted fix before merge.
  • src/commands/reset.ts (missing --json on dry-run) and src/commands/agents.ts (minor: result.id vs arg id in JSON output)

Important Files Changed

Filename Overview
src/commands/tasks.ts Adds --yes, --json, --dry-run to delete; --json to complete and delegate; help examples everywhere. Dry-run for delete makes a real GET API call (inconsistent with agents rotate dry-run).
src/commands/agents.ts Adds --yes, --json, --dry-run to rotate; help examples to list and create. JSON output uses CLI arg id instead of result.id (minor inconsistency).
src/commands/reset.ts Adds --dry-run with human-readable preview; refactors configDir to be computed before the guard. Missing --json support for dry-run unlike the other two destructive commands.
src/commands/login.ts Help text examples only; no functional changes.
src/commands/stats.ts Help text examples only; no functional changes.
src/commands/status.ts Help text examples only; no functional changes.
src/commands/whoami.ts Help text example only; no functional changes.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    CMD["CLI Command\ne.g. tasks delete, agents rotate, reset"]

    CMD --> DRY{--dry-run?}

    DRY -->|yes, tasks delete| FETCH["GET /tasks/:id\n(real API call)"]
    FETCH --> DRYJSON{--json?}
    DRYJSON -->|yes| OUTJSON1["JSON: { dry_run, would_delete }"]
    DRYJSON -->|no| OUTTXT1["Text: 'Would delete task ...'"]

    DRY -->|yes, agents rotate| DRYJSON2{--json?}
    DRYJSON2 -->|yes| OUTJSON2["JSON: { dry_run, agent_id, action }"]
    DRYJSON2 -->|no| OUTTXT2["Text: 'Would rotate key for agent ...'"]

    DRY -->|yes, reset| OUTTXT3["Text only: list of paths\n(no --json support)"]

    DRY -->|no| YES{"--yes / --force?"}
    YES -->|no| PROMPT["Interactive confirm()"]
    PROMPT -->|cancelled| EXIT["Exit"]
    PROMPT -->|confirmed| ACTION
    YES -->|yes| ACTION["Execute API call / filesystem op"]
    ACTION --> JSON{--json?}
    JSON -->|yes| OUTJSON3["Structured JSON output"]
    JSON -->|no| OUTTXT4["Human-readable text output"]
Loading

Reviews (1): Last reviewed commit: "feat: make CLI agent-friendly (--yes, --..." | Re-trigger Greptile

Comment on lines +194 to 201
if (opts.dryRun) {
const task = await apiCall<Task>("GET", `/tasks/${id}`);
if (opts.json) {
console.log(JSON.stringify({ dry_run: true, would_delete: task }, null, 2));
return;
}
console.log(`Would delete task ${id}: ${task.content}`);
return;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 --dry-run still makes a real network call

tasks delete --dry-run fetches GET /tasks/{id} before exiting, so it still makes a live API request. This is inconsistent with the agents rotate --dry-run path, which makes no API call and simply echoes the action from the CLI argument.

Both approaches are defensible, but the inconsistency is worth noting: an agent using --dry-run to avoid side effects may not expect a network hop. Consider either (a) aligning the two dry-run paths, or (b) documenting this in the help text (e.g. "Preview without deleting — still reads the task from the API").

Comment on lines +22 to +31
if (opts.dryRun) {
const hasConfig = node_fs.existsSync(configDir);
console.log("Dry run — the following would be removed:");
console.log(` - API key from secure storage (if stored)`);
if (hasConfig) {
console.log(` - ${configDir}`);
} else {
console.log(` - ${configDir} (not found)`);
}
return;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 --dry-run has no --json flag on reset

Every other destructive command in this PR (tasks delete, agents rotate) supports --dry-run --json together so agents can machine-parse the preview output. The reset command only emits human-readable text on dry-run and has no --json flag at all.

Since the PR goal is agent-friendliness, consider adding --json to reset and emitting something like:

{ "dry_run": true, "would_remove": ["api_key", "/home/user/.delega"] }

so that agents consuming delega reset --dry-run --json get structured output consistent with the other commands.

Comment on lines +122 to +125
if (opts.json) {
console.log(JSON.stringify({ id, api_key: result.api_key }, null, 2));
return;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 JSON output ignores result.id from API response

The type was updated to { id: string; api_key: string } to reflect that the server now returns an id field, but the JSON output still hard-codes the id from the CLI argument rather than using result.id. In practice these are always the same value, but for consistency with the declared return type it's cleaner to use the server-confirmed value directly. Consider spreading result or using result.id instead of id from the outer scope.

…son, result.id)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@ryanmcmillan ryanmcmillan merged commit e47bb3a into main Mar 25, 2026
2 checks passed
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.

2 participants