Skip to content

Commit 44d6ada

Browse files
committed
feat: add -f/--force flags, CLI reference for LLMs, update messaging
- Add -f/--force flag to delete, delete-scope, and edit commands to skip confirmation prompts (useful for scripts and AI agents) - Remove "Results for:" line from search output for cleaner display - Add standalone CLI reference markdown (decisionnode-cli.md) for LLMs - Update "Two interfaces" messaging: CLI is for you and your AI, MCP server is for your AI and you - Add CLI reference links to docs sidebar and footer
1 parent 26fca34 commit 44d6ada

9 files changed

Lines changed: 159 additions & 35 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ The retrieval is explicit — the AI calls search decisions tool via MCP passing
6565

6666
| | CLI (`decide`) | MCP Server (`decide-mcp`) |
6767
|---|---|---|
68-
| **For** | You | Your AI |
68+
| **For** | You (and your AI) | Your AI (and you) |
6969
| **How** | Terminal commands | Structured JSON over MCP |
7070
| **Does** | Setup, add, search, edit, deprecate, export, import, config | Search, add, update, delete, list, history |
7171

src/cli.ts

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@ async function handleSearch() {
291291
return;
292292
}
293293

294-
console.log(`\n ${c.bold}${c.white}Results for:${c.reset} ${c.dim}"${query}"${c.reset}\n`);
294+
console.log('');
295295

296296
for (const result of results) {
297297
const score = (result.score * 100).toFixed(0);
@@ -513,7 +513,9 @@ async function handleEdit() {
513513
return;
514514
}
515515

516-
if (global) {
516+
const force = args.includes('--force') || args.includes('-f');
517+
518+
if (global && !force) {
517519
console.log(`\n ${c.yellow}!${c.reset} This is a global decision that affects ${c.bold}all projects${c.reset}.`);
518520
const confirm = await prompt(` Continue editing? ${c.dim}(y/N):${c.reset} `);
519521
if (confirm.trim().toLowerCase() !== 'y') {
@@ -572,10 +574,14 @@ async function handleDelete() {
572574
console.log(` ${c.yellow}!${c.reset} This is a global decision that affects ${c.bold}all projects${c.reset}.`);
573575
}
574576

575-
const confirm = await prompt(` Type ${c.bold}"yes"${c.reset} to confirm: `);
576-
if (confirm.trim().toLowerCase() !== 'yes') {
577-
console.log(` ${c.dim}Cancelled.${c.reset}\n`);
578-
return;
577+
const force = args.includes('--force') || args.includes('-f');
578+
579+
if (!force) {
580+
const confirm = await prompt(` Type ${c.bold}"yes"${c.reset} to confirm: `);
581+
if (confirm.trim().toLowerCase() !== 'yes') {
582+
console.log(` ${c.dim}Cancelled.${c.reset}\n`);
583+
return;
584+
}
579585
}
580586

581587
if (global) {
@@ -591,12 +597,14 @@ async function handleDelete() {
591597
// Ignore clean errors during delete flow
592598
}
593599

594-
const renumber = await prompt('Renumber remaining decisions? (y/n): ');
595-
if (renumber.trim().toLowerCase() === 'y') {
596-
const renames = await renumberDecisions(decision.scope);
597-
if (renames.length > 0) {
598-
console.log('\nRenumbered:');
599-
renames.forEach(r => console.log(` ${r}`));
600+
if (!force) {
601+
const renumber = await prompt('Renumber remaining decisions? (y/n): ');
602+
if (renumber.trim().toLowerCase() === 'y') {
603+
const renames = await renumberDecisions(decision.scope);
604+
if (renames.length > 0) {
605+
console.log('\nRenumbered:');
606+
renames.forEach(r => console.log(` ${r}`));
607+
}
600608
}
601609
}
602610
}
@@ -688,15 +696,19 @@ async function handleDeleteScope() {
688696
}
689697

690698
const decisions = await listDecisions(normalizedInput);
699+
const force = args.includes('--force') || args.includes('-f');
700+
691701
console.log(`\n ${c.red}${c.bold}Delete scope${c.reset} ${c.cyan}${normalizedInput}${c.reset} ${c.dim}(${decisions.length} decisions)${c.reset}\n`);
692702
decisions.forEach(d => console.log(` ${c.dim}${c.reset} ${c.cyan}${d.id}${c.reset} ${d.decision.substring(0, 50)}`));
693703

694-
console.log(`\n ${c.yellow}!${c.reset} This cannot be undone.`);
695-
const confirm = await prompt(` Type the scope name to confirm: `);
704+
if (!force) {
705+
console.log(`\n ${c.yellow}!${c.reset} This cannot be undone.`);
706+
const confirm = await prompt(` Type the scope name to confirm: `);
696707

697-
if (confirm.toLowerCase() !== scopeArg.toLowerCase() && confirm.toLowerCase() !== normalizedInput.toLowerCase()) {
698-
console.log(` ${c.dim}Cancelled.${c.reset}\n`);
699-
return;
708+
if (confirm.toLowerCase() !== scopeArg.toLowerCase() && confirm.toLowerCase() !== normalizedInput.toLowerCase()) {
709+
console.log(` ${c.dim}Cancelled.${c.reset}\n`);
710+
return;
711+
}
700712
}
701713

702714
const result = await deleteScope(scopeArg);
@@ -2038,10 +2050,11 @@ function printUsage() {
20382050
console.log(` ${c.cyan}list${c.reset} ${c.dim}List all decisions (includes global)${c.reset}`);
20392051
console.log(` ${c.cyan}get${c.reset} ${c.gray}<id>${c.reset} ${c.dim}View a decision${c.reset}`);
20402052
console.log(` ${c.cyan}search${c.reset} ${c.gray}"query"${c.reset} ${c.dim}Semantic search${c.reset}`);
2041-
console.log(` ${c.cyan}edit${c.reset} ${c.gray}<id>${c.reset} ${c.dim}Edit a decision${c.reset}`);
2053+
console.log(` ${c.cyan}edit${c.reset} ${c.gray}<id>${c.reset} ${c.gray}[-f]${c.reset} ${c.dim}Edit a decision (use -f to skip global confirmation)${c.reset}`);
20422054
console.log(` ${c.cyan}deprecate${c.reset} ${c.gray}<id>${c.reset} ${c.dim}Hide from search (reversible)${c.reset}`);
20432055
console.log(` ${c.cyan}activate${c.reset} ${c.gray}<id>${c.reset} ${c.dim}Re-activate a deprecated decision${c.reset}`);
2044-
console.log(` ${c.cyan}delete${c.reset} ${c.gray}<id>${c.reset} ${c.dim}Permanently delete${c.reset}`);
2056+
console.log(` ${c.cyan}delete${c.reset} ${c.gray}<id>${c.reset} ${c.gray}[-f]${c.reset} ${c.dim}Permanently delete (use -f to skip confirmation)${c.reset}`);
2057+
console.log(` ${c.cyan}delete-scope${c.reset} ${c.gray}<scope>${c.reset} ${c.gray}[-f]${c.reset} ${c.dim}Delete entire scope (use -f to skip confirmation)${c.reset}`);
20452058
console.log('');
20462059
console.log(` ${c.bold}${c.white}Data${c.reset}`);
20472060
console.log(` ${c.cyan}export${c.reset} ${c.gray}[format]${c.reset} ${c.dim}Export (md, json, csv)${c.reset}`);

website/public/decisionnode-cli.md

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
# DecisionNode CLI Reference
2+
3+
> Quick reference for AI agents using the `decide` CLI directly (not via MCP).
4+
5+
---
6+
7+
## When to use the CLI vs MCP
8+
9+
Use the CLI when you need to run shell commands directly (e.g., via a `Bash` tool). Use MCP tools when they're available in your tool list. Both access the same data.
10+
11+
---
12+
13+
## Core Commands
14+
15+
```bash
16+
# Setup
17+
decide init # Initialize project store
18+
decide setup # Configure Gemini API key
19+
20+
# Add decisions
21+
decide add # Interactive add (prompts for scope, decision, rationale, constraints)
22+
decide add -s Backend -d "Use PostgreSQL" -r "Team knows SQL" -c "No MongoDB" # Inline add
23+
decide add -s Security -d "Never store tokens in localStorage" --global # Global (all projects)
24+
decide add -s Backend -d "Use connection pooling" --force # Skip conflict check
25+
26+
# Search
27+
decide search "how should we handle auth?" # Semantic search (active only, includes global)
28+
29+
# View
30+
decide list # List all decisions (includes global)
31+
decide list --scope Backend # Filter by scope
32+
decide list --global # Only global decisions
33+
decide get backend-001 # View full details
34+
decide get global:security-001 # View global decision
35+
36+
# Edit
37+
decide edit backend-001 # Interactive edit
38+
decide edit global:security-001 -f # Skip global confirmation
39+
40+
# Lifecycle
41+
decide deprecate backend-001 # Hide from search, keep embedding (reversible)
42+
decide activate backend-001 # Re-activate, immediately searchable again
43+
44+
# Delete
45+
decide delete backend-001 -f # Permanently delete, skip confirmation
46+
decide delete-scope Backend -f # Delete entire scope, skip confirmation
47+
48+
# Data & maintenance
49+
decide export json # Export to terminal (formats: md, json, csv)
50+
decide export --global # Export global decisions
51+
decide import decisions.json # Import from JSON file
52+
decide check # Show decisions missing embeddings
53+
decide embed # Generate missing embeddings
54+
decide clean # Remove orphaned vectors
55+
decide history # View activity log
56+
decide history --filter cli # Filter by source (cli, mcp, cloud)
57+
decide config # View/set configuration
58+
decide projects # List all initialized projects
59+
```
60+
61+
---
62+
63+
## Decision Structure
64+
65+
```json
66+
{
67+
"id": "backend-001",
68+
"scope": "Backend",
69+
"decision": "Use PostgreSQL for all persistent storage",
70+
"status": "active",
71+
"rationale": "Team expertise, ACID compliance, strong ecosystem",
72+
"constraints": ["No MongoDB", "No SQLite for production data"],
73+
"createdAt": "2024-11-14T09:22:00Z"
74+
}
75+
```
76+
77+
**Fields:** `id` (auto-generated), `scope` (required), `decision` (required), `status` (active/deprecated), `rationale` (optional), `constraints` (optional), `createdAt` (auto).
78+
79+
---
80+
81+
## Flags Summary
82+
83+
| Flag | Commands | Effect |
84+
|------|----------|--------|
85+
| `-f` / `--force` | `delete`, `delete-scope`, `edit` | Skip confirmation prompts |
86+
| `--force` | `add` (inline) | Skip conflict check |
87+
| `--global` | `add`, `list`, `export`, `import` | Use global store (all projects) |
88+
| `--scope <scope>` | `list` | Filter by scope |
89+
| `--overwrite` | `import` | Overwrite existing decisions |
90+
| `--filter <source>` | `history` | Filter by source (`cli`, `mcp`, `cloud`) |
91+
92+
---
93+
94+
## Tips for AI agents
95+
96+
- Always run `decide search` before adding a decision to avoid duplicates.
97+
- Use `--force` on `add` to skip the conflict check when you're sure it's not a duplicate.
98+
- Use `-f` on `delete` and `delete-scope` to avoid interactive prompts that will hang.
99+
- Global decisions (prefixed `global:`) apply to all projects. Use them for cross-cutting concerns like security or coding standards.
100+
- The CLI logs the source as `cli`. MCP logs the client name (e.g. `claude-code`, `cursor`).

website/public/decisionnode-docs.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ The same decision store is accessible from any MCP-compatible tool (Claude Code,
1414

1515
| Interface | For | How |
1616
|-----------|-----|-----|
17-
| **CLI** (`decide` / `decisionnode`) | You | Terminal commands, interactive prompts or inline flags |
18-
| **MCP Server** (`decide-mcp`) | Your AI | Structured JSON over MCP, launched automatically by AI clients |
17+
| **CLI** (`decide` / `decisionnode`) | You and your AI | Terminal commands, interactive prompts or inline flags |
18+
| **MCP Server** (`decide-mcp`) | Your AI and you | Structured JSON over MCP, launched automatically by AI clients |
1919

2020
Both read and write to the same local store at `~/.decisionnode/`.
2121

@@ -174,7 +174,7 @@ A decision is a scoped JSON object:
174174
|--------|-----------|-----------|---------------|
175175
| `active` | Yes | Preserved | Default state |
176176
| `deprecated` | No | Preserved | `decide deprecate <id>` or `update_decision(status="deprecated")` |
177-
| (deleted) | N/A | Removed | `decide delete <id>` or `delete_decision(id)` |
177+
| (deleted) | N/A | Removed | `decide delete <id> [-f]` or `delete_decision(id)` |
178178

179179
Re-activate a deprecated decision: `decide activate <id>` — immediately searchable again.
180180

@@ -284,11 +284,11 @@ All commands work with both `decide` and `decisionnode`.
284284
| `decide list --global` | List only global decisions |
285285
| `decide get <id>` | View full details (supports `global:` prefix) |
286286
| `decide search "<query>"` | Semantic search (active only, includes global) |
287-
| `decide edit <id>` | Edit decision fields (supports `global:` prefix) |
287+
| `decide edit <id> [-f]` | Edit decision fields (supports `global:` prefix, use `-f` to skip global confirmation) |
288288
| `decide deprecate <id>` | Hide from search, keep embedding |
289289
| `decide activate <id>` | Re-activate, immediately searchable |
290-
| `decide delete <id>` | Permanently delete decision + embedding |
291-
| `decide delete-scope <scope>` | Delete entire scope |
290+
| `decide delete <id> [-f]` | Permanently delete decision + embedding (use `-f` to skip confirmation) |
291+
| `decide delete-scope <scope> [-f]` | Delete entire scope (use `-f` to skip confirmation) |
292292

293293
### Data & Maintenance
294294

website/src/components/Footer.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ export default function Footer() {
5959
<ul className="space-y-2">
6060
<li><a href="https://github.com/decisionnode/decisionnode" target="_blank" rel="noopener noreferrer" className="text-white/50 hover:text-white transition-colors">GitHub</a></li>
6161
<li><a href="/decisionnode-docs.md" target="_blank" rel="noopener" className="text-white/50 hover:text-white transition-colors">Full Docs (Markdown)</a></li>
62+
<li><a href="/decisionnode-cli.md" target="_blank" rel="noopener" className="text-white/50 hover:text-white transition-colors">CLI Reference (Markdown)</a></li>
6263
<li><Link to="/docs/workflows" className="text-white/50 hover:text-white transition-colors">Workflows</Link></li>
6364
</ul>
6465
</div>

website/src/layouts/DocsLayout.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,16 @@ export default function DocsLayout() {
309309
decisionnode-docs.md
310310
<ExternalLink className="w-3 h-3 ml-auto opacity-50" />
311311
</a>
312+
<a
313+
href="/decisionnode-cli.md"
314+
target="_blank"
315+
rel="noopener"
316+
className="flex items-center gap-2 px-3 py-2.5 lg:py-2 rounded-md text-sm font-medium transition-colors border-l-2 border-transparent text-zinc-400 hover:text-zinc-200 hover:border-zinc-700"
317+
>
318+
<Terminal className="w-4 h-4" />
319+
decisionnode-cli.md
320+
<ExternalLink className="w-3 h-3 ml-auto opacity-50" />
321+
</a>
312322
</div>
313323
</div>
314324
</nav>

website/src/pages/HomePage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,7 @@ export default function HomePage() {
441441
<section className="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 py-20 border-b border-white/5 relative z-10">
442442
<h2 className="text-2xl font-bold text-white mb-3 text-center">Two interfaces, one store</h2>
443443
<p className="text-zinc-500 text-center mb-12 max-w-2xl mx-auto">
444-
The CLI is for you. The MCP server is for your AI. Both read and write to the same local data.
444+
The CLI is for you and your AI. The MCP server is for your AI and you. Both read and write to the same local data.
445445
</p>
446446

447447
<div className="grid md:grid-cols-2 gap-6">

website/src/pages/docs/CliReferencePage.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ export default function CliReferencePage() {
4141
desc: "Semantically search decisions using vector embeddings. Only returns active decisions — deprecated decisions are excluded. Automatically includes global decisions. Requires a Gemini API key."
4242
},
4343
{
44-
cmd: "decide edit <id>",
45-
desc: "Interactively edit a decision's text, rationale, and constraints. Supports global: prefix."
44+
cmd: "decide edit <id> [-f]",
45+
desc: "Interactively edit a decision's text, rationale, and constraints. Supports global: prefix. Use -f or --force to skip global decision confirmation."
4646
},
4747
{
4848
cmd: "decide deprecate <id>",
@@ -53,12 +53,12 @@ export default function CliReferencePage() {
5353
desc: "Re-activate a deprecated decision. Immediately searchable again since the embedding is preserved. Supports global: prefix."
5454
},
5555
{
56-
cmd: "decide delete <id>",
57-
desc: "Permanently delete a decision and its embedding. Supports global: prefix. Consider deprecating instead if you might want it back."
56+
cmd: "decide delete <id> [-f]",
57+
desc: "Permanently delete a decision and its embedding. Supports global: prefix. Use -f or --force to skip confirmation. Consider deprecating instead if you might want it back."
5858
},
5959
{
60-
cmd: "decide delete-scope <scope>",
61-
desc: "Delete an entire scope and all decisions within it."
60+
cmd: "decide delete-scope <scope> [-f]",
61+
desc: "Delete an entire scope and all decisions within it. Use -f or --force to skip confirmation."
6262
},
6363
];
6464

website/src/pages/docs/DocsIntroduction.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,11 +103,11 @@ export default function DocsIntroduction() {
103103
</p>
104104
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mt-4">
105105
<div className="bg-zinc-900/50 p-5 rounded-lg border border-zinc-800">
106-
<p className="text-zinc-200 font-semibold mb-2">CLI — for you</p>
106+
<p className="text-zinc-200 font-semibold mb-2">CLI — for you and your AI</p>
107107
<p className="text-sm">The <code>decide</code> command. Use it to set up projects, add decisions, search, export/import, check embedding health, and configure settings. Supports interactive prompts or <Link to="/docs/cli#core-commands" className="text-primary-400 hover:underline">one-command inline flags</Link>.</p>
108108
</div>
109109
<div className="bg-zinc-900/50 p-5 rounded-lg border border-zinc-800">
110-
<p className="text-zinc-200 font-semibold mb-2">MCP server — for your AI</p>
110+
<p className="text-zinc-200 font-semibold mb-2">MCP server — for your AI and you</p>
111111
<p className="text-sm">The <code>decide-mcp</code> binary. Connect it once (e.g. <code>claude mcp add decisionnode -s user decide-mcp</code> for Claude Code) and the AI calls tools like <code>search_decisions</code> and <code>add_decision</code> over <a href="https://modelcontextprotocol.io" className="text-primary-400 hover:underline" target="_blank" rel="noopener noreferrer">MCP</a>. Works with Claude Code, Cursor, Windsurf, Antigravity, or any MCP-compliant tool.</p>
112112
</div>
113113
</div>

0 commit comments

Comments
 (0)