Skip to content

Commit 1174776

Browse files
authored
Merge pull request #2 from triggerdotdev/chore/pre-publish-fixes
chore: pre-publish fixes from review
2 parents 8d31c34 + a9d67d3 commit 1174776

File tree

16 files changed

+152
-772
lines changed

16 files changed

+152
-772
lines changed

README.md

Lines changed: 90 additions & 558 deletions
Large diffs are not rendered by default.

docs/content/docs/cli/collect.mdx

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,16 @@ agentcrumbs collect
1717

1818
### Agent workflow
1919

20-
When an agent needs to debug something, it should start the collector itself:
20+
When an agent needs to debug something, it should start the collector, clear old crumbs, reproduce, and query:
2121

2222
```bash
23-
# Start collector in background
2423
agentcrumbs collect --quiet &
25-
26-
# Run the service with crumbs enabled
24+
agentcrumbs clear
2725
AGENTCRUMBS=1 node app.js
28-
29-
# ... reproduce the issue ...
30-
31-
# Query the trail
32-
agentcrumbs query --since 5m
26+
agentcrumbs query
3327
```
3428

35-
The agent owns the collector lifecycle. Start it before debugging, query the results, stop it when done. The `--quiet` flag keeps it from cluttering stdout.
29+
Clear before reproducing so you only see crumbs from this run. No `--since` guessing needed. The `--quiet` flag keeps the collector from cluttering stdout.
3630

3731
### Options
3832

docs/content/docs/workflow.mdx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,9 @@ The agent starts the [collector](/cli/collect) (if it isn't already running), re
2727

2828
```bash
2929
agentcrumbs collect --quiet &
30+
agentcrumbs clear
3031
AGENTCRUMBS=1 node app.js
31-
agentcrumbs query --since 5m --ns auth-service
32+
agentcrumbs query --ns auth-service
3233
```
3334

3435
Now the agent sees what executed, in what order, with what data. It can trace the root cause directly instead of reading source and guessing.

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
".": {
1010
"import": "./dist/index.js",
1111
"types": "./dist/index.d.ts"
12+
},
13+
"./test": {
14+
"import": "./dist/sinks/memory.js",
15+
"types": "./dist/sinks/memory.d.ts"
1216
}
1317
},
1418
"bin": {

skills/agentcrumbs/cli/SKILL.md

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,15 @@ Run it in the background before launching the service under test, then
4343
query or tail after reproducing the issue. Stop it when you're done.
4444

4545
```bash
46-
# Start collector in background, run the service, query results
46+
# Start collector, clear old crumbs, reproduce, query
4747
agentcrumbs collect --quiet &
48-
AGENTCRUMBS=1 node app.js &
49-
# ... reproduce the bug ...
50-
agentcrumbs query --since 5m
51-
# When done, kill the collector
52-
kill %1
48+
agentcrumbs clear
49+
AGENTCRUMBS=1 node app.js
50+
agentcrumbs query
5351
```
5452

55-
This is the normal workflow: you own the collector lifecycle.
53+
Clear before reproducing so you only see crumbs from this run.
54+
No `--since` needed when you clear first.
5655

5756
```bash
5857
agentcrumbs collect

skills/agentcrumbs/core/SKILL.md

Lines changed: 10 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -18,166 +18,25 @@ sources:
1818
- "triggerdotdev/trigger-labs:debug-mode/README.md"
1919
---
2020

21-
# agentcrumbs — Core Debug Tracing
22-
23-
agentcrumbs is a zero-overhead debug tracing library. When `AGENTCRUMBS`
24-
is unset, every call is a frozen noop. When enabled, structured events
25-
flow to a collector or stderr.
26-
27-
## Workflow
28-
29-
**Add crumbs as you write code, not after.** When you're building a new
30-
feature, implementing a fix, or writing any code — drop crumbs inline as
31-
part of the work. Don't wait until something breaks to add tracing. Treat
32-
crumbs as part of writing the code itself, like writing a test alongside
33-
the implementation. Every function you write, every branch you add, every
34-
API call you make — add a crumb. Assume debugging will happen later and
35-
your future self will thank you for the visibility.
36-
37-
Crumbs live on the feature branch throughout the PR lifecycle. They are
38-
stripped by `agentcrumbs strip` right before the PR is merged. They never
39-
ship to main. They cost nothing to add and everything to not have when
40-
you need them.
41-
42-
**You can also add crumbs directly to files in `node_modules/`.** This
43-
is useful for tracing into library internals — understanding what a
44-
dependency is actually doing, what arguments it receives, what it returns.
45-
No `// @crumbs` markers needed (gitignored). No import needed either —
46-
just paste a raw `fetch()` call:
47-
48-
```javascript
49-
fetch("http://localhost:8374/crumb", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ ts: new Date().toISOString(), ns: "library-name", msg: "what is happening", type: "crumb", dt: 0, pid: process.pid, data: { relevantVar } }) }).catch(() => {});
50-
```
51-
52-
A fresh `npm install` resets everything.
53-
54-
When reviewing PRs: do not flag `// @crumbs` markers, `#region @crumbs`
55-
blocks, or data logged in crumbs. These are temporary and will be removed
56-
pre-merge.
57-
58-
## Setup
59-
60-
```typescript
61-
import { trail } from "agentcrumbs"; // @crumbs
62-
const crumb = trail("my-service"); // @crumbs
63-
64-
crumb("user logged in", { userId: "123", method: "oauth" }); // @crumbs
65-
```
66-
67-
Enable with the `AGENTCRUMBS` env var, strip before merge:
68-
69-
```bash
70-
AGENTCRUMBS=1 node app.js
71-
agentcrumbs strip # remove all marked crumb code before merge
72-
agentcrumbs strip --check # CI gate — fails if markers found
73-
```
21+
# agentcrumbs — Core Patterns
7422

75-
## Crumb Markers
23+
Setup: `import { trail } from "agentcrumbs"; // @crumbs` then `const crumb = trail("ns"); // @crumbs`
7624

77-
**Every crumb line must be marked** so `agentcrumbs strip` can remove it.
25+
Markers: single-line `// @crumbs` | block `// #region @crumbs` ... `// #endregion @crumbs`
7826

79-
Single-line: append `// @crumbs` to any crumb line:
27+
## Patterns
8028

8129
```typescript
82-
import { trail } from "agentcrumbs"; // @crumbs
83-
const crumb = trail("auth-service"); // @crumbs
84-
crumb("checkpoint", { step: 1 }); // @crumbs
85-
```
86-
87-
Block: wrap multi-line crumb code in `#region @crumbs` (collapsible in editors):
88-
89-
```typescript
90-
// #region @crumbs
91-
const session = crumb.session("debug-flow");
92-
session.crumb("step 1", { data });
93-
session.crumb("step 2", { moreData });
94-
session.end();
95-
// #endregion @crumbs
96-
```
97-
98-
## Core Patterns
99-
100-
### Drop a crumb with structured data and tags
101-
102-
```typescript
103-
import { trail } from "agentcrumbs"; // @crumbs
104-
const crumb = trail("auth-service"); // @crumbs
105-
10630
crumb("token validated", { userId: "u_123", expiresIn: 3600 }); // @crumbs
107-
crumb("cache miss", { key: "users:123" }, { tags: ["perf", "cache"] }); // @crumbs
108-
```
109-
110-
### Create child trails with inherited context
111-
112-
```typescript
113-
import { trail } from "agentcrumbs"; // @crumbs
114-
const crumb = trail("api-gateway"); // @crumbs
115-
116-
function handleRequest(req: Request) {
117-
const reqCrumb = crumb.child({ requestId: req.id, path: req.url }); // @crumbs
118-
reqCrumb("handling request"); // @crumbs
119-
120-
const dbCrumb = reqCrumb.child({ database: "primary" }); // @crumbs
121-
dbCrumb("executing query", { sql: "SELECT ..." }); // @crumbs
122-
}
123-
```
124-
125-
### Measure timing with block markers
126-
127-
```typescript
128-
function processOrder(order: Order) {
129-
// #region @crumbs
130-
crumb.time("process-order");
131-
// #endregion @crumbs
132-
133-
const result = chargePayment(order);
134-
135-
// #region @crumbs
136-
crumb.timeEnd("process-order", { amount: result.amount });
137-
// #endregion @crumbs
138-
139-
return result;
140-
}
141-
```
142-
143-
### Guard expensive debug arguments
144-
145-
```typescript
146-
// #region @crumbs
147-
if (crumb.enabled) {
148-
crumb("full state dump", { state: structuredClone(largeObject) });
149-
}
150-
// #endregion @crumbs
31+
crumb("cache miss", { key }, { tags: ["perf", "cache"] }); // @crumbs
32+
const reqCrumb = crumb.child({ requestId: req.id }); // @crumbs — inherited context
33+
crumb.time("op"); /* ... */ crumb.timeEnd("op", { rows }); // @crumbs — timing
34+
if (crumb.enabled) { crumb("dump", { state: structuredClone(big) }); } // @crumbs — guard expensive args
15135
```
15236

153-
## AGENTCRUMBS Environment Variable
154-
155-
A single env var controls everything. Non-JSON values are shorthand:
156-
157-
| Value | Effect |
158-
|-------|--------|
159-
| `1`, `*`, `true` | Enable all namespaces |
160-
| `auth-*` | Enable matching namespaces (raw string treated as filter) |
161-
| `{"ns":"auth-*,api-*"}` | JSON config with namespace filter |
162-
| `{"ns":"* -internal-*"}` | Wildcard with exclusions |
163-
| `{"ns":"*","port":9999}` | Custom collector port |
164-
| `{"ns":"*","format":"json"}` | JSON output to stderr |
165-
| (unset) | Disabled — all calls are noop |
166-
167-
## The Noop Guarantee
168-
169-
When `trail()` is called and the namespace is disabled, it returns a pre-frozen noop function. There is no per-call `if (enabled)` check. The function body is empty.
170-
171-
```typescript
172-
// When AGENTCRUMBS is unset:
173-
const crumb = trail("my-service"); // returns frozen NOOP
174-
crumb("msg", { data }); // empty function, returns undefined
175-
crumb.child({ x: 1 }); // returns same NOOP
176-
crumb.scope("op", fn); // calls fn() directly
177-
crumb.wrap("name", fn); // returns original fn
178-
```
37+
## Noop Guarantee
17938

180-
The noop check happens once at `trail()` creation time, not on every call.
39+
When disabled, `trail()` returns a frozen noop. No per-call check. `crumb.child()` returns same noop. `crumb.scope("op", fn)` calls `fn()` directly. `crumb.wrap("name", fn)` returns original `fn`.
18140

18241
## Common Mistakes
18342

src/cli/args.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export function getFlag(args: string[], flag: string): string | undefined {
2+
const idx = args.indexOf(flag);
3+
if (idx === -1 || idx + 1 >= args.length) return undefined;
4+
return args[idx + 1];
5+
}
6+
7+
export function hasFlag(args: string[], flag: string): boolean {
8+
return args.includes(flag);
9+
}

src/cli/commands/collect.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { CollectorServer } from "../../collector/server.js";
22
import { formatCrumbPretty } from "../format.js";
3+
import { getFlag, hasFlag } from "../args.js";
34
import type { Crumb } from "../../types.js";
45

56
const DEFAULT_PORT = 8374;
@@ -8,7 +9,7 @@ export async function collect(args: string[]): Promise<void> {
89
const portStr = getFlag(args, "--port");
910
const port = portStr ? parseInt(portStr, 10) : DEFAULT_PORT;
1011
const storeDir = getFlag(args, "--dir");
11-
const quiet = args.includes("--quiet");
12+
const quiet = hasFlag(args, "--quiet");
1213

1314
const server = new CollectorServer(port, storeDir ?? undefined);
1415

@@ -40,8 +41,3 @@ export async function collect(args: string[]): Promise<void> {
4041
process.on("SIGTERM", shutdown);
4142
}
4243

43-
function getFlag(args: string[], flag: string): string | undefined {
44-
const idx = args.indexOf(flag);
45-
if (idx === -1 || idx + 1 >= args.length) return undefined;
46-
return args[idx + 1];
47-
}

src/cli/commands/follow.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ import path from "node:path";
22
import os from "node:os";
33
import { CrumbStore } from "../../collector/store.js";
44
import { formatCrumbPretty, formatCrumbJson } from "../format.js";
5+
import { getFlag, hasFlag } from "../args.js";
56

67
export async function follow(args: string[]): Promise<void> {
78
const traceId = getFlag(args, "--trace");
8-
const json = args.includes("--json");
9+
const json = hasFlag(args, "--json");
910

1011
if (!traceId) {
1112
process.stderr.write("Usage: agentcrumbs follow --trace <traceId> [--json]\n");
@@ -38,9 +39,3 @@ export async function follow(args: string[]): Promise<void> {
3839
}
3940
}
4041
}
41-
42-
function getFlag(args: string[], flag: string): string | undefined {
43-
const idx = args.indexOf(flag);
44-
if (idx === -1 || idx + 1 >= args.length) return undefined;
45-
return args[idx + 1];
46-
}

src/cli/commands/query.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@ import os from "node:os";
33
import type { Crumb } from "../../types.js";
44
import { CrumbStore } from "../../collector/store.js";
55
import { formatCrumbPretty, formatCrumbJson } from "../format.js";
6+
import { getFlag, hasFlag } from "../args.js";
67

78
export async function query(args: string[]): Promise<void> {
89
const ns = getFlag(args, "--ns");
910
const tag = getFlag(args, "--tag");
1011
const since = getFlag(args, "--since");
1112
const session = getFlag(args, "--session");
1213
const match = getFlag(args, "--match");
13-
const json = args.includes("--json");
14+
const json = hasFlag(args, "--json");
1415
const limit = parseInt(getFlag(args, "--limit") ?? "100", 10);
1516

1617
const store = new CrumbStore(path.join(os.homedir(), ".agentcrumbs"));
@@ -79,8 +80,3 @@ function parseSince(since: string): number {
7980
return Date.now() - value * multipliers[unit]!;
8081
}
8182

82-
function getFlag(args: string[], flag: string): string | undefined {
83-
const idx = args.indexOf(flag);
84-
if (idx === -1 || idx + 1 >= args.length) return undefined;
85-
return args[idx + 1];
86-
}

0 commit comments

Comments
 (0)