docket-agent 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,132 @@
1
+ // Minimal YAML subset parser/emitter — enough for loop frontmatter, zero deps.
2
+ //
3
+ // Supported: nested maps, lists of scalars, quoted/unquoted scalars,
4
+ // booleans, null, numbers, `[]` empty lists, `#` comment lines.
5
+ // Deliberately NOT supported: anchors, multi-line scalars, flow maps,
6
+ // lists of maps. Loop files never need them; keeping the grammar small
7
+ // keeps the format auditable.
8
+
9
+ export function parseYaml(text) {
10
+ const lines = [];
11
+ for (const raw of text.split(/\r?\n/)) {
12
+ const trimmed = raw.trim();
13
+ if (!trimmed || trimmed.startsWith('#')) continue;
14
+ lines.push({ indent: raw.match(/^ */)[0].length, content: trimmed });
15
+ }
16
+ let i = 0;
17
+
18
+ function parseScalar(s) {
19
+ if (s === 'null' || s === '~') return null;
20
+ if (s === 'true') return true;
21
+ if (s === 'false') return false;
22
+ if (s === '[]') return [];
23
+ if (s === '{}') return {};
24
+ if (/^-?\d+(\.\d+)?$/.test(s)) return Number(s);
25
+ if (s.startsWith('"') && s.endsWith('"') && s.length >= 2) {
26
+ try {
27
+ return JSON.parse(s); // unescape \" and \\ — the emitter uses JSON quoting
28
+ } catch {
29
+ return s.slice(1, -1);
30
+ }
31
+ }
32
+ if (s.startsWith("'") && s.endsWith("'") && s.length >= 2) {
33
+ return s.slice(1, -1).replace(/''/g, "'");
34
+ }
35
+ return s;
36
+ }
37
+
38
+ function parseBlock(indent) {
39
+ if (i >= lines.length) return null;
40
+ return lines[i].content.startsWith('- ') || lines[i].content === '-'
41
+ ? parseList(indent)
42
+ : parseMap(indent);
43
+ }
44
+
45
+ function parseMap(indent) {
46
+ const obj = {};
47
+ while (i < lines.length) {
48
+ const line = lines[i];
49
+ if (line.indent !== indent || line.content.startsWith('- ')) break;
50
+ const m = line.content.match(/^([^:]+):(.*)$/);
51
+ if (!m) throw new Error(`docket: cannot parse frontmatter line: "${line.content}"`);
52
+ const key = m[1].trim();
53
+ const rest = m[2].trim();
54
+ i++;
55
+ if (rest === '') {
56
+ if (i < lines.length && lines[i].indent > indent) {
57
+ obj[key] = parseBlock(lines[i].indent);
58
+ } else if (
59
+ // Common hand-written style: list items at the same indent as the key.
60
+ i < lines.length &&
61
+ lines[i].indent === indent &&
62
+ (lines[i].content.startsWith('- ') || lines[i].content === '-')
63
+ ) {
64
+ obj[key] = parseList(indent);
65
+ } else {
66
+ obj[key] = null;
67
+ }
68
+ } else {
69
+ obj[key] = parseScalar(rest);
70
+ }
71
+ }
72
+ return obj;
73
+ }
74
+
75
+ function parseList(indent) {
76
+ const arr = [];
77
+ while (i < lines.length) {
78
+ const line = lines[i];
79
+ if (line.indent !== indent || !(line.content.startsWith('- ') || line.content === '-')) break;
80
+ const rest = line.content === '-' ? '' : line.content.slice(2).trim();
81
+ i++;
82
+ arr.push(rest === '' ? null : parseScalar(rest));
83
+ }
84
+ return arr;
85
+ }
86
+
87
+ const result = parseBlock(0);
88
+ if (i < lines.length) {
89
+ throw new Error(`docket: unexpected indentation near: "${lines[i].content}"`);
90
+ }
91
+ return result ?? {};
92
+ }
93
+
94
+ function needsQuotes(s) {
95
+ return (
96
+ s === '' ||
97
+ /^[\s#\-?:@&*!|>%'"[\]{}]/.test(s) ||
98
+ /[:#]\s/.test(s) ||
99
+ /\s$/.test(s) ||
100
+ ['null', 'true', 'false', '~'].includes(s) ||
101
+ /^-?\d+(\.\d+)?$/.test(s)
102
+ );
103
+ }
104
+
105
+ function emitScalar(v) {
106
+ if (v === null || v === undefined) return 'null';
107
+ if (typeof v === 'boolean' || typeof v === 'number') return String(v);
108
+ const s = String(v);
109
+ return needsQuotes(s) ? JSON.stringify(s) : s;
110
+ }
111
+
112
+ export function dumpYaml(value, indent = 0) {
113
+ const pad = ' '.repeat(indent);
114
+ if (Array.isArray(value)) {
115
+ if (value.length === 0) return '';
116
+ return value.map((v) => `${pad}- ${emitScalar(v)}`).join('\n') + '\n';
117
+ }
118
+ if (value && typeof value === 'object') {
119
+ let out = '';
120
+ for (const [k, v] of Object.entries(value)) {
121
+ if (Array.isArray(v)) {
122
+ out += v.length === 0 ? `${pad}${k}: []\n` : `${pad}${k}:\n${dumpYaml(v, indent + 2)}`;
123
+ } else if (v && typeof v === 'object') {
124
+ out += `${pad}${k}:\n${dumpYaml(v, indent + 2)}`;
125
+ } else {
126
+ out += `${pad}${k}: ${emitScalar(v)}\n`;
127
+ }
128
+ }
129
+ return out;
130
+ }
131
+ return `${pad}${emitScalar(value)}\n`;
132
+ }
@@ -0,0 +1,59 @@
1
+ ---
2
+ name: client-follow-up
3
+ description: Follow up with a client with the whole history in the room — promises, tone, and the language they already approved.
4
+ version: 1
5
+ warrant:
6
+ read:
7
+ - account history
8
+ - past email threads with this client
9
+ - meeting notes
10
+ - the contract and current scope
11
+ draft:
12
+ - follow-up email
13
+ - status summary
14
+ - meeting agenda
15
+ change:
16
+ - internal notes on the account
17
+ send: []
18
+ ask:
19
+ - anything the client will see
20
+ - scheduling anything on the client's calendar
21
+ never:
22
+ - unapproved prices, discounts, or scope changes
23
+ - apologizing for things we did not do
24
+ reserved:
25
+ - what gets promised
26
+ - final approval of every outbound message
27
+ - when a relationship problem escalates to a phone call
28
+ record:
29
+ - promises found in the history and whether each is kept, pending, or slipped
30
+ - approved language reused, and any new language that needs sign-off
31
+ - what the draft deliberately does not mention, and why
32
+ ---
33
+
34
+ # Brief
35
+
36
+ - Who this client is: names, roles, who actually decides, who just replies fastest.
37
+ - Every promise made to them, with dates. A follow-up that forgets a promise is worse
38
+ than no follow-up.
39
+ - Approved language vs rejected language. If a phrase was walked back once, it does
40
+ not come back.
41
+ - Their tone preferences: some clients want three bullet points, some want warmth
42
+ first. This client's preference is written here, not guessed each time.
43
+ - Open commercial context: renewal date, expansion talks, any sore spots.
44
+
45
+ # Procedure
46
+
47
+ 1. Reconstruct the state of the relationship from the history before writing a word:
48
+ last contact, open items, promises due.
49
+ 2. Lead with what they care about, not what we did. Status they asked for first,
50
+ housekeeping last.
51
+ 3. Reuse approved language wherever it exists. New claims and new commitments get
52
+ flagged in the draft, not smuggled in.
53
+ 4. Match the established tone. Do not escalate warmth or formality without a reason.
54
+ 5. Deliver the draft with a short cover note: what changed since last time, what needs
55
+ approval, what was left out on purpose.
56
+
57
+ Failure modes: re-promising something that already slipped (reads as not paying
58
+ attention), inventing enthusiasm the history doesn't support, and burying the one
59
+ thing the client actually asked about.
@@ -0,0 +1,55 @@
1
+ ---
2
+ name: cross-tool-memory
3
+ description: One context you own, readable from Claude, GPT, Kimi, or Codex — a model switch is a recompile, not a re-teach.
4
+ version: 1
5
+ warrant:
6
+ read:
7
+ - the loops in this .docket directory
8
+ - existing CLAUDE.md, AGENTS.md, and rules files
9
+ draft:
10
+ - updates to loop brief sections
11
+ - compiled context blocks
12
+ change:
13
+ - CLAUDE.md, AGENTS.md, and other compiled context files via docket compile
14
+ send: []
15
+ ask:
16
+ - rewriting a loop's warrant or reserved sections
17
+ - deleting anything from memory
18
+ never:
19
+ - storing secrets, tokens, or passwords in any loop file
20
+ reserved:
21
+ - what gets remembered at all — memory is curation, not accumulation
22
+ - any change to what an agent is allowed to do
23
+ record:
24
+ - what was added to memory and its source
25
+ - what was pruned and why
26
+ - which context files were regenerated
27
+ ---
28
+
29
+ # Brief
30
+
31
+ - The context lives here, in plain files, in your repo — not inside any one
32
+ assistant's opaque memory feature. The assistants are interchangeable; this
33
+ directory is not.
34
+ - Which tools are in play (Claude Code, Cursor, Codex, a local model) and which
35
+ compiled file each one reads.
36
+ - The curation standard: memory holds things that change future answers —
37
+ decisions, preferences, constraints, standards. Not transcripts.
38
+
39
+ # Procedure
40
+
41
+ 1. After significant work in any tool, harvest: what was decided, what preference
42
+ was expressed, what standard emerged? One line each, into the right loop's
43
+ Brief section.
44
+ 2. Prune as often as you add. Memory that grows without curation becomes noise
45
+ with a table of contents.
46
+ 3. Warrant and reserved-list changes are never harvested automatically — a human
47
+ relaxing a rule once in conversation is not the rule changing.
48
+ 4. Run `docket compile --target claude --write` and `--target agents --write` so
49
+ every tool reads the same brain. The generated blocks are disposable; the loops
50
+ are the source of truth.
51
+ 5. When switching models, carry nothing by hand. If the new tool starts cold,
52
+ something belongs in a loop file that isn't there yet — fix the file, not the chat.
53
+
54
+ Failure mode: letting one tool's built-in memory become the real memory. The moment
55
+ that happens, your context has a landlord.
@@ -0,0 +1,59 @@
1
+ ---
2
+ name: insurance-appeal
3
+ description: Build the appeal, cite the policy, assemble the evidence packet — stop before send.
4
+ version: 1
5
+ warrant:
6
+ read:
7
+ - policy documents
8
+ - denial letter
9
+ - claim correspondence
10
+ - medical records already in the claim file
11
+ draft:
12
+ - appeal letter
13
+ - evidence summary
14
+ - timeline of the claim
15
+ change: []
16
+ send: []
17
+ ask:
18
+ - contacting the insurer
19
+ - contacting the doctor's office
20
+ - requesting new records
21
+ never:
22
+ - accepting or rejecting a settlement
23
+ - inventing symptoms or events not in the record
24
+ reserved:
25
+ - whether to appeal at all
26
+ - the final wording of anything the insurer will read
27
+ - signing and sending
28
+ record:
29
+ - every policy clause cited, with section numbers
30
+ - documents consulted and documents that could not be found
31
+ - claims made in the draft that lack a source in the record
32
+ - where the draft stopped and what a human must do next
33
+ ---
34
+
35
+ # Brief
36
+
37
+ - Policy number, plan year, and the exact denial reason code from the letter.
38
+ - The claim's timeline so far: dates of service, submission, denial, any prior calls.
39
+ - Appeals in this plan have a deadline (often 180 days from denial) — the date matters
40
+ more than the prose.
41
+ - What has already been said to the insurer. Never contradict the record.
42
+ - The insured person's actual account of events — the draft may only use what they
43
+ have confirmed, not what would be convenient.
44
+
45
+ # Procedure
46
+
47
+ 1. Read the denial letter first. The appeal answers the stated reason, not a general
48
+ sense of unfairness.
49
+ 2. Find the policy language the denial relies on, then the language that cuts the
50
+ other way. Quote both, with section numbers.
51
+ 3. Build the evidence packet: what exists, what's missing, what a human would need to
52
+ request. Missing evidence is listed, not papered over.
53
+ 4. Draft the appeal in plain, factual language. No threats, no speculation, no
54
+ symptoms or events that aren't in the record.
55
+ 5. Stop. The draft ends with a checklist of what the human must verify before sending.
56
+
57
+ Known failure mode — the one this loop exists to prevent: an agent reading frustration
58
+ in a message ("I'm so sick of fighting this claim") as authorization, and sending the
59
+ appeal itself. Frustration is not permission. Nothing in this loop sends anything.
@@ -0,0 +1,62 @@
1
+ ---
2
+ name: marketing-brain
3
+ description: Marketing memory that compounds week over week — the messaging that already worked, the objections that keep coming back, the founder's actual voice.
4
+ version: 1
5
+ warrant:
6
+ read:
7
+ - the positioning doc
8
+ - past campaigns and their results
9
+ - sales call notes
10
+ - competitor claims
11
+ draft:
12
+ - copy variants
13
+ - landing page sections
14
+ - launch posts
15
+ change:
16
+ - the swipe file of language that worked
17
+ send: []
18
+ ask:
19
+ - publishing anywhere public
20
+ - any claim with a number in it
21
+ never:
22
+ - claims about competitors we cannot support
23
+ - invented or made-up customer quotes or statistics
24
+ reserved:
25
+ - what the company is willing to claim in public
26
+ - the line between confident and unsupportable
27
+ - final approval on anything that ships
28
+ record:
29
+ - which surviving positioning lines the draft builds on
30
+ - every claim in the draft, marked supported or needs-evidence
31
+ - new objections or language patterns learned this week, added to the brief
32
+ ---
33
+
34
+ # Brief
35
+
36
+ - Positioning that survived contact with real customers — the lines that made people
37
+ nod, kept verbatim. Also the graveyard: lines that tested well internally and died
38
+ in the wild.
39
+ - The recurring sales objections, in the customers' own words, and the answers that
40
+ actually landed.
41
+ - The founder's language: words they use, words they would never use. Copy that
42
+ doesn't sound like them gets rewritten anyway, so start in their voice.
43
+ - The explicit line between confident and unsupportable. Confident: "the
44
+ fastest way to X". Unsupportable: "the only way to X". This line is policy,
45
+ not taste.
46
+
47
+ # Procedure
48
+
49
+ 1. Read the brief before writing. The whole value of this loop is that week 30
50
+ starts where week 29 ended, not from a blank page.
51
+ 2. Draft from surviving language outward. New angles are welcome but marked as
52
+ untested.
53
+ 3. Every factual claim gets a tag: supported (with the source) or needs-evidence.
54
+ A claim without a tag doesn't ship.
55
+ 4. After anything ships, write down what happened — the memory only compounds if
56
+ results flow back in.
57
+ 5. Never resolve the bold-vs-unsupported call alone. When a line sits on the border,
58
+ it goes to the human with the argument for each side.
59
+
60
+ Failure mode: drift. Fifty small rewrites by a helpful agent and the company sounds
61
+ like everyone else. The memory file is the anchor; when in doubt, sound like the
62
+ founder, not like marketing.
@@ -0,0 +1,59 @@
1
+ ---
2
+ name: ticket-handoff
3
+ description: Turn messy work into tickets another human — or another agent — can pick up cold: source, owner, status, blocker, warrant, record.
4
+ version: 1
5
+ warrant:
6
+ read:
7
+ - the conversation or incident being handed off
8
+ - the existing backlog
9
+ - team ownership docs
10
+ draft:
11
+ - ticket title and body
12
+ - suggested owner and priority
13
+ change:
14
+ - ticket status on tickets this loop created
15
+ send: []
16
+ ask:
17
+ - assigning a ticket to a person
18
+ - setting priority above default
19
+ - closing anyone else's ticket
20
+ never:
21
+ - deleting tickets
22
+ - editing another person's ticket description
23
+ reserved:
24
+ - who actually owns what
25
+ - priority calls that affect other people's weeks
26
+ record:
27
+ - every ticket created, with a link back to its source
28
+ - what was NOT filed, and why (duplicate, out of scope, needs a human call)
29
+ - open questions the ticket could not answer
30
+ ---
31
+
32
+ # Brief
33
+
34
+ - The team's real ownership map — who owns which surface, including the unofficial
35
+ truths ("the doc says infra, but ask Dana first").
36
+ - Ticket conventions: title format, required fields, what counts as a blocker vs a
37
+ dependency, the priority scale as actually used.
38
+ - The backlog's known duplicates and graveyards, so the same ghost doesn't get filed
39
+ a fourth time.
40
+ - What a good ticket looks like here: reproducible, scoped, with the source linked —
41
+ not a paragraph of vibes.
42
+
43
+ # Procedure
44
+
45
+ 1. Every ticket carries six fields or it isn't done: source (where this came from,
46
+ linked), owner (suggested, not assigned), status, blocker, warrant (what the
47
+ assignee may and may not do), and record (what evidence closes it).
48
+ 2. Search the backlog before filing. A duplicate found is a record line, not a
49
+ new ticket.
50
+ 3. Write the ticket so a stranger could start it cold. If it needs the original
51
+ conversation to make sense, the ticket isn't finished — the whole point is that
52
+ the context travels with the work.
53
+ 4. Suggest owner and priority with reasons; a human confirms both. Suggesting is
54
+ drafting, assigning is sending.
55
+ 5. Close the handoff with the record: filed, skipped, and unresolved — so the next
56
+ agent (or human) trusts the state without re-reading everything.
57
+
58
+ Failure mode: tickets that are really just chat transcripts with a title. Handing off
59
+ work means handing off the context, the warrant, and the definition of done.
@@ -0,0 +1,54 @@
1
+ ---
2
+ name: travel-morning
3
+ description: Plan a morning in an unfamiliar city around how you actually travel — not how a guidebook thinks you should.
4
+ version: 1
5
+ warrant:
6
+ read:
7
+ - maps and transit schedules
8
+ - opening hours
9
+ - reviews
10
+ - weather
11
+ draft:
12
+ - the morning plan
13
+ - a backup plan for rain or closures
14
+ change: []
15
+ send: []
16
+ ask:
17
+ - any reservation or booking
18
+ - anything that costs money
19
+ never:
20
+ - booking anything nonrefundable
21
+ reserved:
22
+ - spending money
23
+ - changing the day's anchor commitments (flights, meetings, people)
24
+ record:
25
+ - total walking distance and longest single stretch
26
+ - which preferences shaped the plan and which were traded off
27
+ - what was rejected and why (too far, too crowded, violates a food rule)
28
+ ---
29
+
30
+ # Brief
31
+
32
+ - Walking tolerance: how far is pleasant, how far is a death march. Uphill counts double.
33
+ - Food rules: allergies, hard nos, and "will try anything once" — these are different
34
+ categories and must not be blended.
35
+ - Known time-sinks this traveler refuses: queues over 20 minutes, attractions that
36
+ exist for photos, anything requiring a timed ticket bought three days ago.
37
+ - Pace: one anchor thing per morning, or a packed itinerary? Written here, not inferred
38
+ from enthusiasm the night before.
39
+ - Hard constraints of the day: checkout times, meeting times, who else is coming.
40
+
41
+ # Procedure
42
+
43
+ 1. Start from the day's fixed points and work backward — the plan serves the
44
+ commitments, not the reverse.
45
+ 2. Pick one anchor (the thing that would make the morning feel worth it), then arrange
46
+ food and wandering around it.
47
+ 3. Check everything against the rules: distance, opening hours, food constraints,
48
+ queue reputation. A plan that violates a written rule is wrong even if it's great.
49
+ 4. Always produce the rain/closure fallback. A plan with no plan B is half a plan.
50
+ 5. Present the plan with its tradeoffs stated ("skipped X because it's 40 minutes of
51
+ walking uphill") so the human can overrule with full information.
52
+
53
+ Failure mode: optimizing for "top ten" lists instead of the written preferences.
54
+ The whole point of this loop is that the preferences are already known.
@@ -0,0 +1,55 @@
1
+ ---
2
+ name: weekly-planning
3
+ description: Propose the week — priorities, tradeoffs, and what has to move — but change nothing.
4
+ version: 1
5
+ warrant:
6
+ read:
7
+ - calendar
8
+ - task list
9
+ - last week's plan and what actually happened
10
+ draft:
11
+ - the week plan
12
+ - proposed moves with reasons
13
+ change: []
14
+ send: []
15
+ ask:
16
+ - moving any calendar event
17
+ - declining any meeting
18
+ - anything involving other people's time
19
+ never:
20
+ - family dinners, family commitments, or family events
21
+ - workouts or workout blocks
22
+ - cancelling anything without an explicit yes on that specific thing
23
+ reserved:
24
+ - what actually matters this week
25
+ - every calendar change, one by one — approving the plan is not approving the moves
26
+ record:
27
+ - the proposed plan and every tradeoff it makes
28
+ - what got protected and what got sacrificed
29
+ - the difference between last week's plan and last week's reality
30
+ ---
31
+
32
+ # Brief
33
+
34
+ - Standing priorities and their real order — not the aspirational order.
35
+ - Recurring constraints: family commitments, workouts, school pickup, the meeting that
36
+ cannot move even though everyone wishes it could.
37
+ - The rules for what can move: deep work can shift within a day; anything with another
38
+ human in it needs their consent, which means it needs my approval first.
39
+ - How much focused work per day is realistic. Last week's reality is the calibration,
40
+ not last week's intention.
41
+
42
+ # Procedure
43
+
44
+ 1. Start with reality: diff last week's plan against what actually happened. Carry the
45
+ lesson, not the guilt.
46
+ 2. Place the immovables first — the reserved list above is a hard floor, not a
47
+ preference.
48
+ 3. Fit the top priorities into the remaining space. If they don't fit, say so — a plan
49
+ that pretends everything fits is a lie with a nice layout.
50
+ 4. Propose specific moves with reasons: "move X to Thursday because Y". Never make the
51
+ move. The plan is a proposal; the calendar is someone else's to change.
52
+ 5. End with tradeoffs, stated plainly: what this week's plan gives up and why.
53
+
54
+ Failure mode: silently rescheduling things to make the plan look clean. A tidy plan
55
+ that moved a family dinner is a failed plan, even if nobody notices until Thursday.