Skip to content

Commit 880ac3e

Browse files
committed
Add TLDR standard for agent-first CLI discovery
Implement TLDR v0.1 specification providing machine-readable command metadata for AI agents. Every command now accepts --tldr and --tldr=json flags. Key features: - Central metadata registry in src/cli/tldr.ts - Global index: forest --tldr lists all commands - Per-command detail: forest <cmd> --tldr shows full metadata - ASCII mode (default): Single-pass parseable KEY: value pairs - JSON mode: Structured format for programmatic parsing Enables zero-shot CLI discovery for agents with minimal token usage. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
1 parent 5f6170c commit 880ac3e

13 files changed

Lines changed: 954 additions & 13 deletions

File tree

src/cli/commands/admin-recompute-embeddings.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@ import { computeEmbeddingForNode, embeddingsEnabled } from '../../lib/embeddings
1010
import { classifyScore, computeScore, normalizeEdgePair } from '../../lib/scoring';
1111

1212
import { edgeIdentifier, handleError } from '../shared/utils';
13+
import { COMMAND_TLDR, emitTldrAndExit } from '../tldr';
1314

1415
type ClercModule = typeof import('clerc');
1516

1617
type AdminRecomputeEmbeddingsFlags = {
1718
rescore?: boolean;
19+
tldr?: string;
1820
};
1921

2022
export function createAdminRecomputeEmbeddingsCommand(clerc: ClercModule) {
@@ -27,10 +29,19 @@ export function createAdminRecomputeEmbeddingsCommand(clerc: ClercModule) {
2729
type: Boolean,
2830
description: 'Rescore all edges after computing embeddings',
2931
},
32+
tldr: {
33+
type: String,
34+
description: 'Output command metadata for agent consumption (--tldr or --tldr=json)',
35+
},
3036
},
3137
},
3238
async ({ flags }) => {
3339
try {
40+
// Handle TLDR request first
41+
if (flags.tldr !== undefined) {
42+
const jsonMode = flags.tldr === 'json';
43+
emitTldrAndExit(COMMAND_TLDR['admin.recompute-embeddings'], jsonMode);
44+
}
3445
await runAdminRecomputeEmbeddings(flags as AdminRecomputeEmbeddingsFlags);
3546
} catch (error) {
3647
handleError(error);

src/cli/commands/capture.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
printExplore,
1313
} from '../shared/explore';
1414
import { linkAgainstExisting } from '../shared/linking';
15+
import { COMMAND_TLDR, emitTldrAndExit } from '../tldr';
1516

1617
type ClercModule = typeof import('clerc');
1718

@@ -26,6 +27,7 @@ type CaptureFlags = {
2627
noPreview?: boolean;
2728
previewSuggestionsOnly?: boolean;
2829
json?: boolean;
30+
tldr?: string;
2931
};
3032

3133
export function createCaptureCommand(clerc: ClercModule) {
@@ -78,10 +80,19 @@ export function createCaptureCommand(clerc: ClercModule) {
7880
type: Boolean,
7981
description: 'Emit JSON output for the capture summary',
8082
},
83+
tldr: {
84+
type: String,
85+
description: 'Output command metadata for agent consumption (--tldr or --tldr=json)',
86+
},
8187
},
8288
},
8389
async ({ flags }) => {
8490
try {
91+
// Handle TLDR request first
92+
if (flags.tldr !== undefined) {
93+
const jsonMode = flags.tldr === 'json';
94+
emitTldrAndExit(COMMAND_TLDR.capture, jsonMode);
95+
}
8596
await runCapture(flags as CaptureFlags);
8697
} catch (error) {
8798
handleError(error);
@@ -90,6 +101,9 @@ export function createCaptureCommand(clerc: ClercModule) {
90101
);
91102
}
92103

104+
// TODO: Refactor to use createNodeCore() from src/core/nodes.ts
105+
// This function currently reimplements node creation logic that should be
106+
// in the core layer. See CLAUDE.md "3-Layer Architecture" section.
93107
async function runCapture(flags: CaptureFlags) {
94108
const bodyResult = await resolveBodyInput(flags.body, flags.file, flags.stdin);
95109
const body = bodyResult.value;

src/cli/commands/edges.ts

Lines changed: 87 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
resolveSuggestionReference,
1919
} from '../shared/edges';
2020
import { formatId, handleError, getEdgePrefix } from '../shared/utils';
21+
import { COMMAND_TLDR, emitTldrAndExit } from '../tldr';
2122

2223
import type { HandlerContext } from '@clerc/core';
2324

@@ -28,25 +29,30 @@ type EdgesListFlags = {
2829
limit?: number;
2930
longIds?: boolean;
3031
json?: boolean;
32+
tldr?: string;
3133
};
3234

3335
type EdgesProposeFlags = {
3436
limit?: number;
3537
longIds?: boolean;
3638
json?: boolean;
39+
tldr?: string;
3740
};
3841

3942
type EdgesPromoteFlags = {
4043
minScore?: number;
44+
tldr?: string;
4145
};
4246

4347
type EdgesSweepFlags = {
4448
range?: string;
4549
maxScore?: number;
50+
tldr?: string;
4651
};
4752

4853
type EdgesExplainFlags = {
4954
json?: boolean;
55+
tldr?: string;
5056
};
5157

5258
export function registerEdgesCommands(cli: ClercInstance, clerc: ClercModule) {
@@ -68,10 +74,19 @@ export function registerEdgesCommands(cli: ClercInstance, clerc: ClercModule) {
6874
type: Boolean,
6975
description: 'Emit JSON output',
7076
},
77+
tldr: {
78+
type: String,
79+
description: 'Output command metadata for agent consumption (--tldr or --tldr=json)',
80+
},
7181
},
7282
},
7383
async ({ flags }: { flags: EdgesProposeFlags }) => {
7484
try {
85+
// Handle TLDR request first
86+
if (flags.tldr !== undefined) {
87+
const jsonMode = flags.tldr === 'json';
88+
emitTldrAndExit(COMMAND_TLDR['edges.propose'], jsonMode);
89+
}
7590
await runEdgesPropose(flags);
7691
} catch (error) {
7792
handleError(error);
@@ -90,10 +105,19 @@ export function registerEdgesCommands(cli: ClercInstance, clerc: ClercModule) {
90105
description: 'Minimum score to accept',
91106
default: getAutoAcceptThreshold(),
92107
},
108+
tldr: {
109+
type: String,
110+
description: 'Output command metadata for agent consumption (--tldr or --tldr=json)',
111+
},
93112
},
94113
},
95114
async ({ flags }: { flags: EdgesPromoteFlags }) => {
96115
try {
116+
// Handle TLDR request first
117+
if (flags.tldr !== undefined) {
118+
const jsonMode = flags.tldr === 'json';
119+
emitTldrAndExit(COMMAND_TLDR['edges.promote'], jsonMode);
120+
}
97121
await runEdgesPromote(flags);
98122
} catch (error) {
99123
handleError(error);
@@ -107,9 +131,20 @@ export function registerEdgesCommands(cli: ClercInstance, clerc: ClercModule) {
107131
name: 'edges accept',
108132
description: 'Promote a single suggestion by progressive ID, short pair, or edge id',
109133
parameters: ['<ref>'],
134+
flags: {
135+
tldr: {
136+
type: String,
137+
description: 'Output command metadata for agent consumption (--tldr or --tldr=json)',
138+
},
139+
},
110140
},
111-
async ({ parameters }: { parameters: { ref?: string } }) => {
141+
async ({ parameters, flags }: { parameters: { ref?: string }; flags?: { tldr?: string } }) => {
112142
try {
143+
// Handle TLDR request first
144+
if (flags?.tldr !== undefined) {
145+
const jsonMode = flags.tldr === 'json';
146+
emitTldrAndExit(COMMAND_TLDR['edges.accept'], jsonMode);
147+
}
113148
await runEdgesAccept(parameters.ref);
114149
} catch (error) {
115150
handleError(error);
@@ -123,9 +158,20 @@ export function registerEdgesCommands(cli: ClercInstance, clerc: ClercModule) {
123158
name: 'edges reject',
124159
description: 'Reject and remove a suggestion by progressive ID, short pair, or edge id',
125160
parameters: ['<ref>'],
161+
flags: {
162+
tldr: {
163+
type: String,
164+
description: 'Output command metadata for agent consumption (--tldr or --tldr=json)',
165+
},
166+
},
126167
},
127-
async ({ parameters }: { parameters: { ref?: string } }) => {
168+
async ({ parameters, flags }: { parameters: { ref?: string }; flags?: { tldr?: string } }) => {
128169
try {
170+
// Handle TLDR request first
171+
if (flags?.tldr !== undefined) {
172+
const jsonMode = flags.tldr === 'json';
173+
emitTldrAndExit(COMMAND_TLDR['edges.reject'], jsonMode);
174+
}
129175
await runEdgesReject(parameters.ref);
130176
} catch (error) {
131177
handleError(error);
@@ -147,10 +193,19 @@ export function registerEdgesCommands(cli: ClercInstance, clerc: ClercModule) {
147193
type: Number,
148194
description: 'Reject suggestions at or below this score',
149195
},
196+
tldr: {
197+
type: String,
198+
description: 'Output command metadata for agent consumption (--tldr or --tldr=json)',
199+
},
150200
},
151201
},
152202
async ({ flags }: { flags: EdgesSweepFlags }) => {
153203
try {
204+
// Handle TLDR request first
205+
if (flags.tldr !== undefined) {
206+
const jsonMode = flags.tldr === 'json';
207+
emitTldrAndExit(COMMAND_TLDR['edges.sweep'], jsonMode);
208+
}
154209
await runEdgesSweep(flags);
155210
} catch (error) {
156211
handleError(error);
@@ -169,10 +224,19 @@ export function registerEdgesCommands(cli: ClercInstance, clerc: ClercModule) {
169224
type: Boolean,
170225
description: 'Emit JSON output',
171226
},
227+
tldr: {
228+
type: String,
229+
description: 'Output command metadata for agent consumption (--tldr or --tldr=json)',
230+
},
172231
},
173232
},
174233
async ({ parameters, flags }: { parameters: { ref?: string }; flags: EdgesExplainFlags }) => {
175234
try {
235+
// Handle TLDR request first
236+
if (flags.tldr !== undefined) {
237+
const jsonMode = flags.tldr === 'json';
238+
emitTldrAndExit(COMMAND_TLDR['edges.explain'], jsonMode);
239+
}
176240
await runEdgesExplain(parameters.ref, flags);
177241
} catch (error) {
178242
handleError(error);
@@ -186,9 +250,20 @@ export function registerEdgesCommands(cli: ClercInstance, clerc: ClercModule) {
186250
name: 'edges undo',
187251
description: 'Undo the last accept/reject action for a link',
188252
parameters: ['<ref>'],
253+
flags: {
254+
tldr: {
255+
type: String,
256+
description: 'Output command metadata for agent consumption (--tldr or --tldr=json)',
257+
},
258+
},
189259
},
190-
async ({ parameters }: { parameters: { ref?: string } }) => {
260+
async ({ parameters, flags }: { parameters: { ref?: string }; flags?: { tldr?: string } }) => {
191261
try {
262+
// Handle TLDR request first
263+
if (flags?.tldr !== undefined) {
264+
const jsonMode = flags.tldr === 'json';
265+
emitTldrAndExit(COMMAND_TLDR['edges.undo'], jsonMode);
266+
}
192267
await runEdgesUndo(parameters.ref);
193268
} catch (error) {
194269
handleError(error);
@@ -215,6 +290,10 @@ export function registerEdgesCommands(cli: ClercInstance, clerc: ClercModule) {
215290
type: Boolean,
216291
description: 'Emit JSON output',
217292
},
293+
tldr: {
294+
type: String,
295+
description: 'Output command metadata for agent consumption (--tldr or --tldr=json)',
296+
},
218297
},
219298
help: {
220299
notes: [
@@ -240,6 +319,11 @@ export function registerEdgesCommands(cli: ClercInstance, clerc: ClercModule) {
240319
},
241320
async ({ flags }: { flags: EdgesListFlags }) => {
242321
try {
322+
// Handle TLDR request first
323+
if (flags.tldr !== undefined) {
324+
const jsonMode = flags.tldr === 'json';
325+
emitTldrAndExit(COMMAND_TLDR.edges, jsonMode);
326+
}
243327
await runEdgesList(flags);
244328
} catch (error) {
245329
handleError(error);

src/cli/commands/explore.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
parseDate,
88
} from '../shared/utils';
99
import { printExplore, selectNode } from '../shared/explore';
10+
import { COMMAND_TLDR, emitTldrAndExit } from '../tldr';
1011

1112
type ClercModule = typeof import('clerc');
1213

@@ -84,10 +85,19 @@ export function createExploreCommand(clerc: ClercModule) {
8485
type: Boolean,
8586
description: 'Prompt to choose a match',
8687
},
88+
tldr: {
89+
type: String,
90+
description: 'Output command metadata for agent consumption (--tldr or --tldr=json)',
91+
},
8792
},
8893
},
8994
async ({ flags, parameters }) => {
9095
try {
96+
// Handle TLDR request first
97+
if (flags.tldr !== undefined) {
98+
const jsonMode = flags.tldr === 'json';
99+
emitTldrAndExit(COMMAND_TLDR.explore, jsonMode);
100+
}
91101
const limitFlag =
92102
typeof flags.limit === 'number' && !Number.isNaN(flags.limit) ? flags.limit : undefined;
93103
const neighborhoodLimit = limitFlag ?? DEFAULT_NEIGHBORHOOD_LIMIT;

0 commit comments

Comments
 (0)