@mnbny/woof 0.0.0-stage → 0.1.1

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.
Files changed (61) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +510 -2
  3. package/cli/templates/add-draft.md +22 -0
  4. package/cli/templates/add-error.md +5 -0
  5. package/cli/templates/add-result.md +11 -0
  6. package/cli/templates/edit-draft.md +24 -0
  7. package/cli/templates/edit-error.md +3 -0
  8. package/cli/templates/edit-path.md +3 -0
  9. package/cli/templates/edit-result.md +7 -0
  10. package/cli/templates/edit-unchanged.md +3 -0
  11. package/cli/templates/editor.html +338 -0
  12. package/cli/templates/explain-ambiguous.md +5 -0
  13. package/cli/templates/explain-error.md +5 -0
  14. package/cli/templates/explain-result.md +5 -0
  15. package/cli/templates/export-error.md +3 -0
  16. package/cli/templates/export-result.md +8 -0
  17. package/cli/templates/get-ambiguous.md +5 -0
  18. package/cli/templates/get-cancelled.md +5 -0
  19. package/cli/templates/get-candidates.md +5 -0
  20. package/cli/templates/get-error.md +5 -0
  21. package/cli/templates/get-home-dependencies.md +1 -0
  22. package/cli/templates/get-no-match.md +3 -0
  23. package/cli/templates/get-search-empty.md +3 -0
  24. package/cli/templates/get-search.md +5 -0
  25. package/cli/templates/import-backup.md +7 -0
  26. package/cli/templates/import-choice-rejected.md +1 -0
  27. package/cli/templates/import-decision.md +18 -0
  28. package/cli/templates/import-error.md +3 -0
  29. package/cli/templates/import-finding-incomplete.md +1 -0
  30. package/cli/templates/import-finding-unreadable.md +1 -0
  31. package/cli/templates/import-findings-configuration.md +3 -0
  32. package/cli/templates/import-findings.md +3 -0
  33. package/cli/templates/import-imported.md +3 -0
  34. package/cli/templates/import-private.md +6 -0
  35. package/cli/templates/import-rechecked.md +1 -0
  36. package/cli/templates/import-rechecks.md +1 -0
  37. package/cli/templates/import-report.md +1 -0
  38. package/cli/templates/import-reusable.md +2 -0
  39. package/cli/templates/import-unchanged.md +1 -0
  40. package/cli/templates/import-validation-findings.md +1 -0
  41. package/cli/templates/init-error.md +3 -0
  42. package/cli/templates/init-home.md +7 -0
  43. package/cli/templates/init-location.md +7 -0
  44. package/cli/templates/init-registered.md +5 -0
  45. package/cli/templates/init-repository.md +5 -0
  46. package/cli/templates/init-target.md +11 -0
  47. package/cli/templates/invocation-error.md +5 -0
  48. package/cli/templates/migration-notice.md +1 -0
  49. package/cli/templates/private-value.md +1 -0
  50. package/cli/templates/private-warning.md +1 -0
  51. package/cli/templates/projects-error.md +3 -0
  52. package/cli/templates/projects-result.md +3 -0
  53. package/cli/templates/readme-error.md +5 -0
  54. package/cli/templates/skill-missing.md +10 -0
  55. package/cli/templates/skill-outdated.md +7 -0
  56. package/cli/templates/validate-ambiguous.md +5 -0
  57. package/cli/templates/validate-error.md +5 -0
  58. package/cli/templates/validate-result.md +3 -0
  59. package/cli/woof.bundle.mjs +246 -0
  60. package/package.json +73 -4
  61. package/skills/woof-execution/SKILL.md +84 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 yulolimum
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,511 @@
1
- # Temporary Holding Version
1
+ <h1 align="center">woof</h1>
2
+ <p align="center">Design tokens for your coding agent's instructions.</p>
2
3
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
4
+ <p align="center">
5
+ <img width="240" height="240" alt="image" src="https://github.com/user-attachments/assets/2a079bf2-b98b-42a3-aea2-156798055599" />
6
+ </p>
7
+
8
+ My prompts, conventions, skills, and scripts were everywhere: copied between repos, stashed in ignored folders, slowly drifting apart. Every new project started the same way. Dig up the last agent file, copy it, fix the few lines that differ. All of it Markdown, and Markdown doesn't compose.
9
+
10
+ Design systems solved this a long time ago. You don't paste a hex code into every component. You name the color once, point an alias like `color.primary` at it, and dark mode changes what the alias means. woof brings that to your agent instructions. You write each convention, prompt, or script once, as a named token. Tokens reference each other and build bigger instructions. Each of your projects overrides only what's different. Keep tokens shared or private, in the repo or out of it.
11
+
12
+ You don't run woof. Your agent does:
13
+
14
+ <img src=".github/assets/readme/commit.jpg" alt="you: use woof to commit this. agent: runs woof get commit convention, finds git.commit, runs woof get git.commit, follows the seven rules of a great commit message, and commits with the message Add export command.">
15
+
16
+ In a repo that overrides `git.commit` with Conventional Commits, the same request gets you `feat(cli): add export command` instead. Nothing copied. A companion skill teaches your agent to search woof, use what it finds, and check with you before it changes anything.
17
+
18
+ ## How it works
19
+
20
+ ### Shared defaults, project overrides
21
+
22
+ Your shared tokens live in your woof home, and your agent can find them from any project. A project overrides only what's different. Everything else comes from the shared tokens.
23
+
24
+ ```text
25
+ shared
26
+ ├─ git.commits.seven_rules "Follow the seven rules of a great commit message…"
27
+ ├─ git.commits.conventional "Use Conventional Commits: type(scope): summary…"
28
+ └─ git.commit → git.commits.seven_rules
29
+
30
+ acme (project)
31
+ └─ git.commit → git.commits.conventional
32
+
33
+ globex (project)
34
+ └─ git.commit "Start every subject with the ticket ID, such as GLX-142…"
35
+ ```
36
+
37
+ `acme` points the alias at the other shared rule. `globex` writes its own. Every other project keeps the seven rules.
38
+
39
+ Say `acme` is your team's repo. Its woof configuration lives in the repo, and everyone gets it through Git. `globex` is a client repo you can't commit to, so its configuration stays private in your woof home. woof finds it by path, worktrees included.
40
+
41
+ ### Build instructions from pieces
42
+
43
+ A token can pull in other tokens with `{{…}}`. Build your agent instructions from pieces you already have:
44
+
45
+ ```text
46
+ agents.instructions
47
+ # Working in this repo
48
+ - Commits: {{git.commit}}
49
+ - Testing: {{testing.policy}}
50
+ - Style: {{code.style}}
51
+ ```
52
+
53
+ Your AGENTS.md or CLAUDE.md shrinks to one line, and the same line works in every repo:
54
+
55
+ ```markdown
56
+ Run `woof get agents.instructions` and follow it.
57
+ ```
58
+
59
+ In `acme`, the commit line comes out as Conventional Commits. In `globex`, it's the ticket rule. You never touch `agents.instructions`.
60
+
61
+ ### Tokens that run
62
+
63
+ A token can also be a bash, node, tsx, or bun script. Some scripts feed your instructions. Others just do a job.
64
+
65
+ ```text
66
+ git.branch bash git branch --show-current
67
+ checks.all bash pnpm lint && pnpm test && pnpm build
68
+ ```
69
+
70
+ `You're on {{git.branch}}.` reads as `You're on feat/export.` And when you say "run the checks", your agent runs `checks.all`. Projects override scripts like any other token, so the same ask does the right thing in every repo.
71
+
72
+ ### Ask in plain words
73
+
74
+ You don't have to remember token names. Give a token a description and tags, and your agent finds it by what it's for. Search reads only names, descriptions, and tags. It never loads every prompt or runs a script, so your agent fetches just the one it needs.
75
+
76
+ The companion skill, `woof-execution`, teaches your agent that loop: search, fetch, follow. It also writes tokens for you, so you never hand-edit JSON. Or Markdown. (Sorry, Markdown. It's not you, it's me.)
77
+
78
+ <img src=".github/assets/readme/save-token.jpg" alt="you: save that review checklist to woof. agent: runs woof get review checklist --search, finds nothing similar, drafts review.checklist with the description PR review checklist, and asks to save it. you: yes. agent: runs woof add review.checklist and saves it.">
79
+
80
+ Edits, sharing, and repo setup work the same way. Your agent proposes, and you approve.
81
+
82
+ ### Share with a coworker
83
+
84
+ If you can commit to a repo, like `acme`, keep its woof configuration there, and Git shares it with your team. Client repos are another story. Your agent instructions don't always belong in someone else's codebase, but your coworkers on that client could still use them. So keep the configuration in your woof home instead, like `globex`, and share it as a file.
85
+
86
+ Ask your agent to export it. woof packs the tokens and files `globex` needs into one zip:
87
+
88
+ <img src=".github/assets/readme/export.jpg" alt="you: share my globex setup with sam. agent: runs woof export --project globex, saves ~/.woof/exports/globex.woof.zip, and says to send it to Sam.">
89
+
90
+ On Sam's side, anything new comes straight in. Anything that differs from what Sam already has waits for Sam's choice, one at a time:
91
+
92
+ <img src=".github/assets/readme/import.jpg" alt="sam: import globex.woof.zip. agent: runs woof import globex.woof.zip, says git.commit is different from theirs, and asks to keep yours, take theirs, or save theirs under a new name. sam: keep mine.">
93
+
94
+ Before it writes anything, woof saves a backup.
95
+
96
+ For values Sam should supply, like staging credentials, ask your agent to mark the token private before you share it. Sam gets a placeholder to fill in.
97
+
98
+ ## Getting started
99
+
100
+ woof runs through npx, so there's nothing to install. You need Node.js 22.13+, 24, or 26+.
101
+
102
+ Paste this into your agent:
103
+
104
+ ```text
105
+ Run `npx @mnbny/woof readme` and set up woof for me.
106
+ ```
107
+
108
+ Your agent reads this guide. The first time it runs woof, woof suggests the companion skill, and your agent asks you before installing it.
109
+
110
+ Next, fill it up. woof is only as good as the tokens you give it, so start with primitives: the conventions, prompts, docs, and skills you already have. Point your agent at them, and it saves each one as a token:
111
+
112
+ - **"Save our commit rules to woof."** Your agent drafts the token, shows it to you, and saves it once you say yes.
113
+ - **"Add the docs in `docs/conventions/` to woof."** Each doc becomes a token with a name and a description your agent can search.
114
+ - **"Turn my code review skill into a woof token."** Its instructions are now available in every project.
115
+ - **"Point my AGENTS.md at woof."** It moves your instructions into tokens and leaves one line behind.
116
+
117
+ Then put them to work:
118
+
119
+ - **"What does woof have for code review?"** It searches names, descriptions, and tags, and shows you what fits.
120
+ - **"Use the woof token for code review."** It fetches the matching token and follows its instructions.
121
+ - **"Use woof to commit this."** It finds your commit convention and follows it.
122
+ - **"Set up woof for this repo."** It creates the repo's woof configuration, committed or private. Your call.
123
+
124
+ ## Under the hood
125
+
126
+ Everything below is plain JSON, and your agent writes it for you. Here's how it fits together, one piece at a time.
127
+
128
+ ### Where tokens live
129
+
130
+ Your shared tokens live in one file in your woof home, `~/.woof/woof.config.json`. Your agent edits it through woof, and you can edit it by hand.
131
+
132
+ ### Tokens
133
+
134
+ A token is a key in that file. Nested keys build its path:
135
+
136
+ ```json
137
+ {
138
+ "git": {
139
+ "commits": {
140
+ "seven_rules": "Follow the seven rules of a great commit message: …"
141
+ }
142
+ }
143
+ }
144
+ ```
145
+
146
+ That's `git.commits.seven_rules`. A plain string is a prompt.
147
+
148
+ To help your agent find a token, swap the string for the long form, with a description and tags:
149
+
150
+ ```json
151
+ {
152
+ "$type": "prompt",
153
+ "$exec": "Follow the seven rules of a great commit message: …",
154
+ "$description": "How to write commit messages",
155
+ "$tags": ["git"]
156
+ }
157
+ ```
158
+
159
+ Keys that start with `$` belong to woof. Everything else is yours to name.
160
+
161
+ For a long prompt, keep it in a file. A plain string or `$exec` can point at it:
162
+
163
+ ```json
164
+ "<root>/resources/review-checklist.md"
165
+ ```
166
+
167
+ `<root>` is your woof home. In a repo's config, `<repo>` points at the repo.
168
+
169
+ ### Aliases
170
+
171
+ A string that is exactly one reference is an alias:
172
+
173
+ ```json
174
+ {
175
+ "git": {
176
+ "commit": "{{git.commits.seven_rules}}"
177
+ }
178
+ }
179
+ ```
180
+
181
+ Point `git.commit` at a different token, and everything that uses it follows.
182
+
183
+ ### Composites
184
+
185
+ References work anywhere in text:
186
+
187
+ ```json
188
+ {
189
+ "agents": {
190
+ "instructions": "# Working in this repo\n\n- Commits: {{git.commit}}\n- Testing: {{testing.policy}}"
191
+ }
192
+ }
193
+ ```
194
+
195
+ woof applies overrides first, then resolves references, so an override reaches every composite. Write `{{{{` and `}}}}` for literal double braces. A missing token or a loop fails before anything runs.
196
+
197
+ ### Scripts
198
+
199
+ Set `$type` to `bash`, `node`, `tsx`, or `bun`, and `$exec` becomes the script. Here's `git.branch`:
200
+
201
+ ```json
202
+ {
203
+ "$type": "bash",
204
+ "$exec": "git branch --show-current"
205
+ }
206
+ ```
207
+
208
+ The script runs in the repo root, and its output becomes the value. `$exec` can also be a file, like `"<root>/scripts/checks.sh"`, or a list of scripts that run in order and stop at the first failure.
209
+
210
+ ### Private values
211
+
212
+ You might keep `globex`'s staging accounts in woof. Ask your agent to mark that token private before you share it with Sam. It adds `$private` to the token:
213
+
214
+ ```json
215
+ {
216
+ "$type": "prompt",
217
+ "$exec": "user1:pass user2:pass",
218
+ "$private": true
219
+ }
220
+ ```
221
+
222
+ You still get the real value locally. The export replaces it with `{{-woof:private-}}`. Sam can import the configuration and ask their agent to fill in their own value. Until then, woof warns whenever their agent uses the token.
223
+
224
+ ### Projects
225
+
226
+ A project changes tokens for one codebase. It holds only what's different, and everything else comes from your shared tokens. A project lives in one of two places.
227
+
228
+ #### In your woof home
229
+
230
+ A private project never enters the repo, so it works even where you can't commit, like `globex`. Ask your agent to set up a private woof project for the repo. It adds the project to your shared file under `$projects`, with the paths that select it:
231
+
232
+ ```json
233
+ {
234
+ "$projects": {
235
+ "globex": {
236
+ "$metadata": {
237
+ "$basePaths": ["~/code/globex"],
238
+ "$worktreePaths": ["~/code/globex-*"]
239
+ },
240
+ "git": {
241
+ "commit": "Start every subject with the ticket ID, such as GLX-142…"
242
+ }
243
+ }
244
+ }
245
+ }
246
+ ```
247
+
248
+ woof selects `globex` anywhere inside `~/code/globex`, and in every worktree that matches `~/code/globex-*`.
249
+
250
+ #### In the repo
251
+
252
+ Ask your agent to set up woof for the repo. It creates a `woof.config.json` at the repo root, or in `.agents/` or `.claude/`. Commit it, and woof uses it whenever you work inside the repo, in any clone or worktree, so your whole team gets it. Here's `acme`'s, which points one alias elsewhere:
253
+
254
+ ```json
255
+ {
256
+ "git": {
257
+ "commit": "{{git.commits.conventional}}"
258
+ }
259
+ }
260
+ ```
261
+
262
+ #### Which project applies
263
+
264
+ woof picks one project per run: the one you name, then the repo's own config, then the private project whose paths match. If nothing matches, your shared tokens apply alone.
265
+
266
+ ## Reference
267
+
268
+ That's the tour. From here, it gets detailed fast: the full config, every rule, and every command. Your agent reads this part closely. You can skim.
269
+
270
+ ### Config schema
271
+
272
+ Here's everything from the tour in one file, `~/.woof/woof.config.json`:
273
+
274
+ ```json
275
+ {
276
+ "$schemaVersion": 2,
277
+ "git": {
278
+ "commits": {
279
+ "seven_rules": {
280
+ "$type": "prompt",
281
+ "$exec": "Follow the seven rules of a great commit message: …",
282
+ "$description": "How to write commit messages",
283
+ "$tags": ["git"]
284
+ },
285
+ "conventional": "Use Conventional Commits: type(scope): summary…"
286
+ },
287
+ "commit": "{{git.commits.seven_rules}}",
288
+ "branch": {
289
+ "$type": "bash",
290
+ "$exec": "git branch --show-current"
291
+ }
292
+ },
293
+ "testing": {
294
+ "policy": "Run the tests before you push."
295
+ },
296
+ "checks": {
297
+ "all": {
298
+ "$type": "bash",
299
+ "$exec": ["pnpm lint", "pnpm test", "pnpm build"]
300
+ }
301
+ },
302
+ "review": {
303
+ "checklist": "<root>/resources/review-checklist.md"
304
+ },
305
+ "agents": {
306
+ "instructions": "# Working in this repo\n\n- Commits: {{git.commit}}\n- Testing: {{testing.policy}}"
307
+ },
308
+ "$projects": {
309
+ "globex": {
310
+ "$metadata": {
311
+ "$basePaths": ["~/code/globex"],
312
+ "$worktreePaths": ["~/code/globex-*"]
313
+ },
314
+ "git": {
315
+ "commit": "Start every subject with the ticket ID, such as GLX-142…"
316
+ }
317
+ },
318
+ "initech": "<root>/projects/initech.json"
319
+ }
320
+ }
321
+ ```
322
+
323
+ And `acme`'s repo config:
324
+
325
+ ```json
326
+ {
327
+ "$schemaVersion": 2,
328
+ "git": {
329
+ "commit": "{{git.commits.conventional}}"
330
+ }
331
+ }
332
+ ```
333
+
334
+ #### Values
335
+
336
+ | Value | Example | Means |
337
+ | --- | --- | --- |
338
+ | String | `"Run the tests before you push."` | Prompt |
339
+ | String that is exactly one reference | `"{{git.commits.seven_rules}}"` | Alias |
340
+ | String with references inside | `"Commits: {{git.commit}}"` | Composite prompt |
341
+ | String that starts with `<root>/` or `<repo>/` | `"<root>/resources/review-checklist.md"` | Prompt read from a file |
342
+ | Object with `$type` | `{ "$type": "bash", "$exec": "…" }` | Resource: a prompt or a script |
343
+ | Any other object | `{ "commits": { … } }` | Namespace |
344
+
345
+ #### Reserved keys
346
+
347
+ | Key | Belongs in | Value |
348
+ | --- | --- | --- |
349
+ | `$schemaVersion` | Every config file, at the top level | `2` |
350
+ | `$type` | A resource | `prompt`, `bash`, `node`, `tsx`, or `bun` |
351
+ | `$exec` | A resource | Prompt text, script source, or a `<root>/` or `<repo>/` file. Scripts also take a list. |
352
+ | `$description` | A resource | Optional text for search |
353
+ | `$tags` | A resource | Optional list of strings for search |
354
+ | `$private` | A resource | Optional boolean. `true` replaces the content with `{{-woof:private-}}` on export. |
355
+ | `$projects` | Your shared file | Private projects by name: inline, or a `<root>/` path to the project's own file, like `initech` |
356
+ | `$metadata` | A private project | Optional `$basePaths` and `$worktreePaths` |
357
+ | `$basePaths` | `$metadata` | Paths that select the project, including everything below them |
358
+ | `$worktreePaths` | `$metadata` | Patterns that match the current directory or one of its parents |
359
+
360
+ #### Rules
361
+
362
+ - Token names use ASCII letters, digits, `_`, and `-`, and they're case-sensitive. Dots join names into a path.
363
+ - An unknown `$` key fails.
364
+ - A value is a string, a resource, or a namespace. Numbers, booleans, `null`, and bare arrays fail.
365
+ - `<root>` is your woof home. `<repo>` is the root of the selected project's checkout: the current checkout inside the project's paths, or else the project's first base path that exists. Without either, `<repo>` files fail. Shared tokens can't use `<repo>`. A file path can't be absolute or empty, can't use `..`, and must resolve to a regular file inside its root.
366
+ - Paths in `$basePaths` and `$worktreePaths` are absolute or start with `~/`. woof ignores paths that don't exist on your machine, so teammates can list their own.
367
+ - Shared tokens must resolve without a project. They can't reference project-only tokens or `<repo>` files.
368
+ - An override replaces the whole token, including its description and tags. A project can't replace a shared namespace with a token, or a token with a namespace.
369
+ - A missing reference or a cycle fails before any script runs. A token that references itself is a cycle.
370
+ - `{{-...-}}` is reserved for internal markers. Add and import remapping reject token addresses that produce this syntax, such as `-draft-`. Write `{{{{-woof:private-}}}}` to show the private marker literally.
371
+ - A checkout holds one repo config: `woof.config.json`, `.agents/woof.config.json`, or `.claude/woof.config.json`. Two different files fail.
372
+ - Every config file declares `"$schemaVersion": 2`. woof never upgrades a file on its own. When it asks for a migration, rerun the command with `--migrate`.
373
+
374
+ ### Commands
375
+
376
+ Your agent runs these as `npx @mnbny/woof <command>`. Add `--help` to any command for its full options.
377
+
378
+ | Command | What it does | Options |
379
+ | --- | --- | --- |
380
+ | `woof readme` | Prints this guide. Agents run it first. | — |
381
+ | `woof get [query…]` | Prints a token's value when the query is its exact path. Otherwise, searches. | `--search` to always search, `--project <name>` |
382
+ | `woof add [path]` | Adds a token | `--type`, `--content`, `--description`, `--tag`, `--private`, and one of `--shared`, `--repo`, or `--project <name>` |
383
+ | `woof edit [path]` | Changes a token's content, description, tags, or privacy | `--content`, `--description`, `--tag`, `--private` or `--no-private`, `--shared` or `--override`, `--project <name>` |
384
+ | `woof init [location]` | Creates a repo config or a private project | `--repo`, or `--name <name>` with `--base-path` and `--worktree-path` |
385
+ | `woof projects` | Shows which project the current directory selects, and lists private projects | — |
386
+ | `woof explain [path]` | Traces how a token resolves, without running scripts | `--project <name>` |
387
+ | `woof validate [path]` | Checks every token, or one token's graph, without running scripts | `--project <name>` |
388
+ | `woof export` | Packs a private project into a zip in `~/.woof/exports/` | `--project <name>` |
389
+ | `woof import <archive>` | Asks about each conflict in an archive, then applies it | `--decisions <file>` |
390
+
391
+ Every command also takes `--agent` and `--migrate`. `woof --help` and `woof --version` work too.
392
+
393
+ #### Options
394
+
395
+ - `--content` takes text, the path of an existing file, or `-` to read standard input.
396
+ - `--tag`, `--base-path`, and `--worktree-path` repeat: `--tag git --tag commits`.
397
+ - In `edit`, an empty `--description` or `--tag` removes it. `--shared` changes a shared token for every project, and `--override` overrides it in the selected project only.
398
+ - `--private` on `add` or `edit` sets `$private: true`. `edit --no-private` removes the field. Other edits preserve the privacy setting. Disabling privacy alone on an already public definition makes no change.
399
+ - A qualified address, such as `'$projects.globex.git.commit'`, selects a project the same way `--project globex` does. Quote it so the shell leaves `$projects` alone.
400
+
401
+ #### Agent mode and exit status
402
+
403
+ - woof detects coding agents from markers in their environment. `--agent` covers any other caller.
404
+ - Agent mode runs the same operations, with plain text and no questions.
405
+ - When a command needs a decision, it prints the choices and the exact command to continue, writes nothing, and exits with status 1.
406
+ - `get` prints the value exactly as resolved, so you can pipe it.
407
+ - Exit status is `0` on success, `1` on a failure or a handoff, and `130` on a cancellation.
408
+
409
+ #### Export and import
410
+
411
+ - Export starts with the selected project's tokens and follows their references after applying overrides. It omits unrelated shared tokens, overridden defaults, and unused files. An empty project exports no shared tokens.
412
+ - A shared token that depends on a project override, directly or through another token, exports as a project token. Independent shared dependencies stay shared.
413
+ - For each exported token with `$private: true`, woof replaces `$exec` with `{{-woof:private-}}` and keeps the token's address, type, metadata, and privacy flag. Files and references used only by the omitted content stay out of the archive.
414
+ - Privacy applies only to the marked token. An unmarked token can still export the same file. Local values and source files stay unchanged, and recovery backups retain private values.
415
+ - Import warns about placeholders and continues. A differing value at the same address in the same layer needs conflict review. A new project token is added even if it overrides a shared token.
416
+ - Each lookup that reaches a private placeholder names the token, asks for its value, and warns on stderr. Replacing the marker with `woof edit` stops the warning and preserves the privacy flag.
417
+
418
+ ### Scripts
419
+
420
+ A script token runs each time your agent gets it, and whatever it prints becomes the value.
421
+
422
+ #### Runtimes
423
+
424
+ - `bash`: your bash.
425
+ - `node`: the same Node.js that runs woof.
426
+ - `tsx`: TypeScript through a pinned tsx, from npx. It doesn't type-check.
427
+ - `bun`: a pinned Bun, from npx.
428
+
429
+ #### Where the script lives
430
+
431
+ `$exec` holds the script itself, or points at a file:
432
+
433
+ - `<root>/…`: a file in your woof home.
434
+ - `<repo>/…`: a file in the selected project's checkout. Project tokens only.
435
+
436
+ #### Notes
437
+
438
+ - Scripts run in the selected project's checkout, the same root as `<repo>`. Without one, they run in the current repo root, or in the current directory outside a repo.
439
+ - A list of scripts runs in order and stops at the first failure.
440
+ - A private placeholder returns a request for the missing value without starting a runtime. If any entry in a script list is a placeholder, none of the list runs.
441
+ - The first `tsx` or `bun` run may need the network.
442
+ - If a script fails, the lookup fails. woof doesn't undo what a script already did, and there's no timeout.
443
+ - Only `get` runs scripts. Searching, `explain`, and `validate` never do.
444
+
445
+ ### Files and folders
446
+
447
+ Everything woof keeps lives in your woof home, `~/.woof`.
448
+
449
+ #### In your woof home
450
+
451
+ - `woof.config.json`: your shared tokens and private projects.
452
+ - `resources/`: files woof copied in for your tokens.
453
+ - `exports/`: archives from `woof export`.
454
+ - `.backups/`: backups that `woof import` saves before it writes.
455
+
456
+ #### In a repo
457
+
458
+ - `woof.config.json`, `.agents/woof.config.json`, or `.claude/woof.config.json`: the repo's project. Keep only one.
459
+
460
+ #### Notes
461
+
462
+ - woof creates its home and `woof.config.json` the first time it needs them.
463
+ - woof keeps every backup. To restore one, extract it over woof home.
464
+
465
+ ### Limits and decisions
466
+
467
+ #### Limits
468
+
469
+ What woof doesn't do yet:
470
+
471
+ - There's no rename, move, or delete command. Edit the JSON by hand, or ask your agent to, then run `woof validate`.
472
+ - One project applies per run, so you can't layer personal overrides on top of a repo's config.
473
+ - Scripts take no arguments. Each run uses the script as written.
474
+ - On Windows, cancelling a script stops the script itself but not the processes it started. macOS and Linux clean up everything.
475
+ - The `woof edit` page loads its styles from a CDN, so it's unstyled offline.
476
+
477
+ #### Deliberate decisions
478
+
479
+ What woof does on purpose:
480
+
481
+ - An override replaces the whole token. To build on a shared value, reference its pieces from your override. A token can't reference itself.
482
+ - A change to a shared token reaches every project at once, the way a design token does. There's no version pinning.
483
+ - Repo configs travel through Git. Only private projects export.
484
+ - Script output is plain text. woof never looks for references in it.
485
+ - A composite that references a script runs it on every lookup, so keep scripts with side effects out of composites.
486
+ - Scripts run as you, with no sandbox, timeout, or undo. Before you get tokens from an unfamiliar repo, check its config with `woof explain`.
487
+ - Search matches names, descriptions, and tags as text. It isn't semantic, so good descriptions pay off.
488
+ - woof borrows design-token ideas, not the DTCG file format, so DTCG tools can't read woof files.
489
+ - woof runs locally and never calls a model. Your agent does the thinking.
490
+
491
+ ## Development
492
+
493
+ ```sh
494
+ git clone https://github.com/mnbny/woof.git
495
+ cd woof
496
+ pnpm install
497
+ node cli/setup.mjs # links ~/.local/bin/woof to this checkout
498
+ pnpm validate # formats, lints, typechecks, and builds
499
+ pnpm test
500
+ ```
501
+
502
+ Design notes for contributors and agents live in [`.agents/docs/`](.agents/docs/index.md).
503
+
504
+ ## ...and why "woof"?
505
+
506
+ <table>
507
+ <tr>
508
+ <td>After this interaction, I refer to my agents as woof.</td>
509
+ <td><img width="256" height="182" alt="telegram-cloud-photo-size-1-4954272345791073203-m" src="https://github.com/user-attachments/assets/d390675f-cf99-4acc-bca8-95a2a6076432" /></td>
510
+ </tr>
511
+ </table>
@@ -0,0 +1,22 @@
1
+ woof needs more input to add a token: {{missing}}.
2
+
3
+ Draft the token from the conversation:
4
+
5
+ 1. Work out what the user wants to keep. Make the content usable without this conversation.
6
+ 2. Check for a similar token with woof get 'TERMS' --search --agent. If one exists, ask the user whether to add a new token or to change the existing token with woof edit 'PATH' --agent.
7
+ 3. Choose a path that fits the existing namespaces below. Each name in the path contains only ASCII letters, digits, underscores and hyphens. Avoid paths such as -draft- whose references use the reserved {{-...-}} marker syntax.
8
+ 4. Choose the type: prompt for instructions or other text, or bash, node, tsx or bun for a script.
9
+ 5. Write a one-line description and a few tags, so that discovery can find the token.
10
+ 6. Choose one target below. Shared tokens are available in every project. A project token exists only in that project, and it overrides a shared token at the same path.
11
+ 7. If the user wants the content omitted from exports, add --private to the command. The token will export with a placeholder. Local access still returns its value.
12
+ 8. Show the user the path, target, type, description, tags, privacy setting and content. Save only after the user approves.
13
+
14
+ Existing namespaces:
15
+ {{namespaces}}
16
+
17
+ Targets:
18
+ {{targets}}
19
+
20
+ Then run this command with the approved values. Put the content between the WOOF lines, so that it goes to standard input:
21
+
22
+ {{command}}
@@ -0,0 +1,5 @@
1
+ woof could not add the token.
2
+
3
+ {{details}}
4
+
5
+ Retry with the complete command.
@@ -0,0 +1,11 @@
1
+ Added {{path}}.
2
+
3
+ Configuration: {{file}}
4
+ Type: {{type}}
5
+ Content: {{content}}
6
+ Description: {{description}}
7
+ Tags: {{tags}}
8
+ Private: {{private}}
9
+ Overrides a shared token: {{override}}
10
+
11
+ Check the token with {{command}}.
@@ -0,0 +1,24 @@
1
+ Edit {{path}}.
2
+
3
+ Type: {{type}}
4
+ Defined in: {{where}}
5
+ Configuration: {{configuration}}
6
+ Content: {{location}}
7
+ Description: {{description}}
8
+ Tags: {{tags}}
9
+ Private: {{private}}
10
+
11
+ Current content:
12
+ {{content}}
13
+
14
+ Layers:
15
+ {{layers}}
16
+
17
+ 1. Work out the change from the conversation.
18
+ 2. Show the user the current and the new version. Apply the change only after the user approves.
19
+ 3. Pass only the fields that change. Tags replace the current set. --description '' removes the description, and --tag '' removes all tags.
20
+ 4. --private replaces the content with a placeholder on export. --no-private removes the privacy flag, so the content can export again. Use only one of these flags. Replacing a placeholder's content preserves the privacy setting unless --no-private is given.
21
+ 5. Put new content between the WOOF lines, so that it goes to standard input. If the content is in a script file, edit that file directly. woof can still change its description, tags and export privacy. To change a shared script for this project only, first run the command with --override alone. woof copies the script into the project and reports the copy. Then edit the copy.
22
+ 6. If the command has LAYER, replace it with one flag from Layers.
23
+
24
+ {{command}}
@@ -0,0 +1,3 @@
1
+ woof could not edit the token.
2
+
3
+ {{details}}
@@ -0,0 +1,3 @@
1
+ Name the token to edit.
2
+
3
+ Find it with woof get 'TERMS' --search{{project}} --agent. Then run woof edit 'PATH'{{project}} --agent to see the current token.
@@ -0,0 +1,7 @@
1
+ Edited {{path}}.
2
+
3
+ Configuration: {{file}}
4
+ Content file: {{contentFile}}
5
+ Changed in: {{where}}
6
+
7
+ Check the token with {{command}}.
@@ -0,0 +1,3 @@
1
+ No changes to {{path}}.
2
+
3
+ The new values match the current token. Nothing was written.