create-evda 0.1.4 → 0.1.6

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 (57) hide show
  1. package/CHANGELOG.md +100 -0
  2. package/README.md +93 -8
  3. package/bin/evda.mjs +437 -5
  4. package/create-evda.mjs +68 -12
  5. package/docs/local-model.md +34 -0
  6. package/hooks/evda-read-guard.mjs +7 -0
  7. package/lib/chat-export.mjs +198 -0
  8. package/lib/circle-plan.mjs +277 -0
  9. package/lib/circles.mjs +479 -28
  10. package/lib/connect.mjs +46 -0
  11. package/lib/day-file.mjs +93 -0
  12. package/lib/declarations.mjs +235 -0
  13. package/lib/devices.mjs +202 -0
  14. package/lib/doctor.mjs +351 -19
  15. package/lib/filechanges.mjs +622 -0
  16. package/lib/folders.mjs +22 -8
  17. package/lib/gather-apply.mjs +635 -0
  18. package/lib/gather.mjs +808 -0
  19. package/lib/grants.mjs +7 -1
  20. package/lib/guard.mjs +132 -0
  21. package/lib/hooks.mjs +124 -0
  22. package/lib/keep-hook.mjs +185 -0
  23. package/lib/kinds.mjs +23 -6
  24. package/lib/kinds.schema.json +2 -1
  25. package/lib/manifest.mjs +14 -1
  26. package/lib/mcp-auth.mjs +370 -0
  27. package/lib/mcp-http.mjs +336 -0
  28. package/lib/mcp.mjs +467 -35
  29. package/lib/migrate-people.mjs +231 -0
  30. package/lib/organize.mjs +52 -12
  31. package/lib/parity.mjs +111 -0
  32. package/lib/presets.mjs +379 -0
  33. package/lib/prompt-hook.mjs +88 -0
  34. package/lib/publish.mjs +264 -0
  35. package/lib/readers.mjs +319 -0
  36. package/lib/records.mjs +52 -0
  37. package/lib/references.mjs +5 -51
  38. package/lib/render.mjs +158 -0
  39. package/lib/roles.mjs +102 -1
  40. package/lib/secret-shape.mjs +58 -0
  41. package/lib/setup.mjs +146 -2
  42. package/lib/skills.mjs +266 -0
  43. package/lib/subrecord.mjs +121 -0
  44. package/lib/sync-rules.mjs +87 -0
  45. package/lib/tools.mjs +120 -29
  46. package/lib/update-check.mjs +146 -0
  47. package/lib/work.mjs +180 -0
  48. package/lib/yaml.mjs +117 -42
  49. package/package.json +25 -15
  50. package/presets/journal/preset.json +19 -0
  51. package/presets/projects-and-areas/preset.json +34 -0
  52. package/skills/evda/SKILL.md +76 -0
  53. package/templates/AGENTS.md +129 -15
  54. package/templates/README.md +15 -1
  55. package/templates/circles-README.md +3 -3
  56. package/templates/evda-digest.md +32 -5
  57. package/LICENSE +0 -21
package/CHANGELOG.md ADDED
@@ -0,0 +1,100 @@
1
+ # Changelog
2
+
3
+ Plain-English notes on how Iris behaves differently after each version. Not a commit log.
4
+
5
+ ## Unreleased
6
+
7
+ A note you asked to have just noted, or a sealed one, stays that way wherever EVDA copies it.
8
+ `evda organize` no longer copies a just-noted capture into its day: the day gets one line saying where
9
+ it is, and once you release it the next organize files its words. Gathering a pile quotes nothing of a
10
+ just-noted file and never asks your AI about it, and the copy it places keeps the flag. Turning a
11
+ person's page into a typed profile never lifts a heading or a quote out of a sealed part. Sync never
12
+ sends a just-noted or sealed note to anyone else's devices because of a `share:` mark.
13
+
14
+ Anything can be sealed: `sealed: true` in a note's frontmatter, or a part of a note fenced as
15
+ ` ```sealed `. Nothing but your own devices opens a sealed note or part, ever. Your agent is never
16
+ shown it or told where it is, whichever AI it is, and no tool lets it unseal one; you unseal by
17
+ editing the file. Publishing leaves a sealed part out of the file it sits in and refuses a sealed
18
+ note outright, `evda doctor` fails a sealed note that carries `share:`, and `evda search` on your own
19
+ device still finds everything, marked `[sealed]`.
20
+
21
+ A hand-written `|` or `>` block in a frontmatter or `eco.yaml` now reads the way every other YAML
22
+ tool reads it: a line starting with `#` inside it (a markdown heading in a description) stays, and
23
+ so do leading blank lines, `|+` trailing newlines and more-indented lines under `>`. Indentation
24
+ indicators such as `|2` are read instead of refused.
25
+
26
+ `evda doctor` no longer reports a person's dated section as missing its observation when the
27
+ observation is worded differently from the heading. An observation dated the same day covers it, one
28
+ observation per section, so a section with none still fails.
29
+
30
+ Setup asks one thing about filing: should your agent file everything you say automatically, or only
31
+ when you ask? Everything is the default. The answer goes in `evda.json` as `"filing"`, and a record
32
+ with no answer gets the question the first time an app connects. In the Claude app, the filing
33
+ instruction now leads each tool's description, which is what the app actually reads, and the
34
+ operating layer opens with five lines for a chat app. One conversation is one `## HH:MM` section of
35
+ the day, not a heading per message. In Claude Code, an owner who chose everything gets a hook that
36
+ files each message as they send it. And `evda gather` takes a Claude.ai or ChatGPT data export
37
+ (`conversations.json`) and adds the messages you wrote there that your record does not already hold,
38
+ under each conversation's date and time, never the model's replies.
39
+
40
+ Your agent says who reads each part of your EVÐA. Setup writes the AI you chose as the reader of
41
+ the whole record, and a circle can name another one, a model on your own computer, or none;
42
+ `evda doctor` prints it under "Read by". Say "just note this" and it is kept where no AI reads it
43
+ until you say it can. When something is held back, your agent says what is there and how you open
44
+ it. The README quotes what each AI company's own pages say about training and retention, with the
45
+ date they were read, and explains how to run a model locally.
46
+
47
+ Iris files what you say without being asked. In Claude Code a Stop hook, installed into the
48
+ record when you pick Claude at setup (or with `evda hook install`), asks once before a session
49
+ ends having read the record or heard you out and filed nothing. In the Claude desktop app and
50
+ ChatGPT, the MCP server adds one line to its results until something is filed. People, projects
51
+ and places with an entry get a dated section when they come up; one without an entry is offered,
52
+ never created.
53
+
54
+ Your EVÐA can reach the Claude phone app. `evda mcp --http` serves the same tools over HTTPS
55
+ through a tunnel you run, and nothing connects until you type a one-time owner code, printed by
56
+ `evda mcp token --new` on the machine that holds the record, into the page Claude opens. The
57
+ connection reads as Claude, so parts of the record you set to be read by another AI stay closed to
58
+ it. `evda mcp token --revoke-all` ends every connection at once.
59
+
60
+ Iris writes down what it repeats. A process done or explained a second time becomes a skill in your
61
+ record, `.claude/skills/<name>/SKILL.md`, and Iris tells you in one line; any app reads it with
62
+ `evda_skills`. It is never a rule about your life. Iris can make an EVÐA inside yours (a project, a
63
+ company, an agent) and tells you what doctor said about it; your own `evda.json` changes only when
64
+ you say yes to its circles stopping there. The day's entry holds your words and one line on what the
65
+ conversation was about, marked as not yours. `evda hook install` and setup now install the read guard
66
+ with the Stop hook, and `evda doctor` says whether each is there.
67
+
68
+ ## 0.1.5
69
+
70
+ Presets: pick a way to organize the record (numbered inbox, projects and areas, or a student
71
+ layout) from a small reviewed library, applied only by adding folders. Nothing already there is
72
+ touched or overwritten.
73
+
74
+ ## 0.1.4
75
+
76
+ Iris can now run through an MCP server, so Claude Code, Codex and the Claude desktop app read
77
+ and write the record without you copying files anywhere. `evda skill install` adds a matching
78
+ Claude Code skill. Captures can be filed into the right day automatically (`evda organize`), and
79
+ the week can be read back for you (`evda look-back`).
80
+
81
+ ## 0.1.3
82
+
83
+ Removed a claim that never worked: pasting AGENTS.md into a ChatGPT or Claude Project's
84
+ instructions field does not run an EVÐA, because that field forgets everything after one
85
+ conversation. Setup now offers a one-time import into a real coding-agent record instead.
86
+
87
+ ## 0.1.2
88
+
89
+ Setup asks one question at a time instead of a wall of prompts, and does not finish until you
90
+ confirm your AI's training setting is off, with a link to where that setting actually lives.
91
+
92
+ ## 0.1.1
93
+
94
+ Added a plain README written for the person who just ran `create-evda`, not for the agent:
95
+ how Iris responds, how it improves from your corrections, and how you improve alongside it.
96
+
97
+ ## 0.1.0
98
+
99
+ First publish. The record itself: a manifest, AGENTS.md as the operating layer, the hypothesis
100
+ ledger, `evda doctor`, and the installer.
package/README.md CHANGED
@@ -4,7 +4,15 @@ EVÐA is a really organized journal that helps you live your life the more you u
4
4
 
5
5
  Iris cannot give you the right answer for your life, but it is really good at suggestions. Take them, push back on what you disagree with, get specific, and get a new response back. Iris keeps your words in your EVÐA as you talk. EVÐA is not a tool to do what you already do a little better: it helps you learn what is worth doing, do that better, revise, and continue. We assume far more about ourselves, our situations and other people than we know, and you learn to be specific about those assumptions.
6
6
 
7
- It is not easy to write down thoughts you have not admitted to yourself, never mind to a friend or a therapist. EVÐA is designed for exactly that, and it is open source to lower that barrier as far as it goes. Your record is plain files on your own machine and it is never accessible to anyone at EVÐA: the company never receives it. The AI you choose does receive what Iris reads, which is why setup has you turn model training off first. Capable open source models you run on your own hardware are the next step, so you know exactly where your words go.
7
+ It is not easy to write down thoughts you have not admitted to yourself, never mind to a friend or a therapist. EVÐA is designed for exactly that, and it is open source so you can check how it works.
8
+
9
+ Your information is stored locally on your own devices as files you can open with anything. When your devices sync, what goes between them is locked with keys only your devices have, so EVÐA can't read it.
10
+
11
+ The AI you choose reads what it needs to think with you. With training turned off, the company behind it says it won't use your information, and that promise is backed by their terms and by law. We can't prove it for them, and I don't want to pretend we can.
12
+
13
+ If you want more than that, you have two options. You can run a model locally on your own computer, and you can just ask how to set it up. Or you can say something is just to be noted, and no AI reads it until you say it can.
14
+
15
+ **Who reads what.** Setup writes the AI you chose into `evda.json` as `read_by`, so it reads the whole record. A circle can name its own reader: another AI, `local` for a model on your own hardware (`evda local-model` says how), or `none`. `evda doctor` prints "Read by" for every part. Say "just note this" and your agent files it with `noted: true` (`evda note` from a terminal); no AI reads it until you say it can (`evda release <path>`), and `evda search` still finds it on your device. The MCP server refuses both in code, `hooks/evda-read-guard.mjs` (installed into the record for Claude owners) stops Claude Code's Read, Grep and shell reads of them, and `AGENTS.md` tells every other agent to decline out loud. None of this is a lock: the words are plain files on your disk, and it stops an agent that checks.
8
16
 
9
17
  EVÐA prescribes no values and no rules. The only requirement is that you want to, and you are open to it. It is built on a neo-Aristotelian philosophy; ask your agent about it, or have any agent verify it by reading this code.
10
18
 
@@ -14,7 +22,7 @@ npx create-evda my-evda
14
22
 
15
23
  ## Setup
16
24
 
17
- On a terminal, `create-evda` asks one question at a time: what to call your agent (Iris unless you rename it), who you are, what you want this for, how it should talk to you, and which AI you will use. It shows where that AI's training setting is, links the provider's own page, and does not finish until you type yes. The answers go into "What this EVÐA is" at the top of `AGENTS.md`, in your words. It suggests dictation: Apple's built in dictation, or Wispr Flow with data collection turned off. Last, it offers to bring in what an AI you already use knows about you; see below.
25
+ On a terminal, `create-evda` asks one question at a time: what to call your agent (Iris unless you rename it), who you are, what you want this for, how to organize it (a preset, or start plain), how it should talk to you, and which AI you will use. It shows where that AI's training setting is, links the provider's own page, and does not finish until you type yes. The answers go into "What this EVÐA is" at the top of `AGENTS.md`, in your words. It suggests dictation: Apple's built in dictation, or Wispr Flow with data collection turned off. Last, it offers to bring in what an AI you already use knows about you; see below.
18
26
 
19
27
  Unattended, nothing is asked:
20
28
 
@@ -23,7 +31,7 @@ npx create-evda my-evda --yes --agent-name Iris --owner "Dana" --purpose "why wo
23
31
  --voice "direct" --platform claude --training-off
24
32
  ```
25
33
 
26
- `--platform` takes `claude`, `chatgpt` (ChatGPT and Codex), `gemini`, `cursor` or `other`. Without `--training-off` the AI line stays empty and the agent asks about training in the first session. A run with no terminal on stdin is treated as `--yes`.
34
+ `--platform` takes `claude`, `chatgpt` (ChatGPT and Codex), `gemini`, `cursor` or `other`. `--preset` takes a preset id or `none`; unattended, no flag means none. Without `--training-off` the AI line stays empty and the agent asks about training in the first session. A run with no terminal on stdin is treated as `--yes`.
27
35
 
28
36
  ## Any AI
29
37
 
@@ -33,20 +41,59 @@ npx create-evda my-evda --yes --agent-name Iris --owner "Dana" --purpose "why wo
33
41
 
34
42
  Setup ends by asking whether to bring in what an AI you already talk to knows about you. Say yes and it prints a prompt: paste that into ChatGPT, Claude, or whatever you use, and it writes out what it remembers or has guessed about you, in plain text. Bring the answer to your first session and your agent files it verbatim under `record/imports/YYYY-MM-DD-<source>.md`, with the source and date at the top. It is filed as what that AI said, never as your own words, and every line in it is a claim to check with you over time, not a fact.
35
43
 
44
+ ## Bringing in a pile you already have
45
+
46
+ Most people already have a record: a Documents folder, a Notes or Obsidian export, a contacts
47
+ export. `evda gather scan <folder or file>...` walks it, types every file (a note, a person, a
48
+ project, an event, a log, a source, a piece, an attachment, a capture), and writes a proposal:
49
+ which preset fits, which folders the pile needs, and where each file would go. It changes nothing
50
+ in what it reads and writes nothing into a record; the proposal is a JSON file under
51
+ `~/.evda/gather/` (or `--out`, or `$EVDA_GATHER_DIR`). Anything an app holds stays there: a
52
+ Contacts card becomes a `contacts:` reference on a person's page and its phone number is never
53
+ copied, and a bookmark becomes a `url:` reference. A file holding a password or token is refused.
54
+
55
+ It asks only what changes a placement, in plain words: whether someone many files mention should
56
+ have a page, whether a project that looks finished is finished or live, whether notes that read
57
+ like therapy get their own circle. `evda gather questions <proposal>` lists them and
58
+ `evda gather answer <proposal> <question> <value>` records one; through the MCP, your AI asks them
59
+ in conversation. `--with-ai` hands the files it could not place to your own `claude -p`.
60
+
61
+ When every question is answered and you say yes, `evda gather apply <proposal> --into <folder>`
62
+ writes it: into a new record made with the proposal's preset, or into the record you name. It
63
+ copies by default (`--move` takes the files out of the pile), keeps references as references,
64
+ writes no share mark and no circle (a circle you asked for is a proposal file), runs `evda doctor`,
65
+ and prints `CHECKED <n> items placed, <m> asked, <k> left for a person`. A plain text note becomes
66
+ `.md` with its bytes unchanged. Every write is listed in a reversal manifest beside the proposal,
67
+ and `evda gather revert <manifest>` puts the pile and the record back byte for byte; it refuses
68
+ when a file it wrote was edited since, unless `--force`. Gathering again later with
69
+ `--into <record>` skips what the record already holds and asks nothing it already decided, and
70
+ apply places only what is new, in the record's own folders.
71
+
36
72
  ## Talk to it from the AI you already use
37
73
 
38
74
  `evda mcp` serves your record as an MCP server on stdio, so Claude Code, Codex and the Claude desktop app can read and write it from any folder. EVÐA holds no API key and calls no model: the AI is yours, signed in as you, and it reaches the record only through these tools.
39
75
 
40
76
  evda_operating_layer AGENTS.md, read first every session
41
77
  evda_recent the last few days of the record
42
- evda_write your words, verbatim, appended to today's daily file. It takes no path and never edits
78
+ evda_write your words, verbatim, appended to today's daily file, with one line of context labeled as not yours. It takes no path and never edits
43
79
  evda_import what another AI said about you, filed under record/imports with its source and date
44
80
  evda_search plain text search inside the record, on this machine
45
81
  evda_circles your circles and their policies
46
82
  evda_propose_circle a proposal file under proposals/. Never a circle, never a grant
83
+ evda_presets the preset library, or one preset's folders
84
+ evda_propose_structure what a preset would add to this record, in plain words. Writes nothing
85
+ evda_apply_preset adds a preset's folders; refused unless confirmed: true, the owner's yes
86
+ evda_gather a pile you already have (a folder, an export), typed and proposed as an EVDA. Moves nothing
87
+ evda_gather_questions what the gather needs you to decide; only what changes where something goes
88
+ evda_gather_answer your answer, recorded on the proposal, and what it re-placed
89
+ evda_gather_apply writes the answered proposal into a record; refused unless confirmed: true, the owner's yes
90
+ evda_skills the skills your agent wrote for itself, or one of them
91
+ evda_write_skill writes or revises a skill at .claude/skills/<name>/SKILL.md. Never outside that folder, never a rule about your life
92
+ evda_create_subrecord an EVÐA inside this one, with the four roles and its own AGENTS.md, then doctor. Your evda.json changes only on bounded with confirmed: true
47
93
  evda_doctor evda doctor, as a report
94
+ evda_check_update whether newer EVDA tooling exists. The only tool that reaches the network
48
95
 
49
- Every write appends, refuses anything shaped like a password, key or token, and says the path it wrote. `evda connect` prints the setup for your record, with its path filled in:
96
+ Every write appends, refuses anything shaped like a password, key or token, and says the path it wrote. The one call that leaves this machine is `evda_check_update` asking the npm registry for a version number; it carries nothing from the record and installs nothing, and the update itself is a command you run in a terminal. `evda connect` prints the setup for your record, with its path filled in:
50
97
 
51
98
  ```bash
52
99
  claude mcp add --scope user evda -- /path/to/node /path/to/evda.mjs mcp ~/my-evda # Claude Code
@@ -57,10 +104,29 @@ For the Claude desktop app, add the same command under `mcpServers` in `claude_d
57
104
 
58
105
  **The skill.** `skills/evda/SKILL.md` (Agent Skills format) tells Claude Code to act as Iris through the tools: load the operating layer first, file verbatim, never quiz, circles only on your yes. `evda skill install` copies it to `~/.claude/skills/evda/`; setup offers it.
59
106
 
107
+ **The record keeps itself.** You never have to say "save this". In Claude Code, setup (when you pick Claude) installs a Stop hook in the record's own `.claude/settings.json`: a session that read the record or heard you out and filed nothing to the day's record is asked once, before it stops, to file your words. It runs only in sessions opened in the record; your global settings are not touched. `evda hook install` adds it to a record made earlier, and `evda doctor` says whether it is installed and current. In apps with no hooks (the Claude desktop app, ChatGPT), the MCP server itself adds one line to its tool results once a conversation has read the record and filed nothing, and goes quiet after the first write.
108
+
109
+ **Filing is the owner's answer.** Setup asks once whether to file everything they say automatically (the default) or only when they ask, and writes it to `evda.json` as `"filing": "everything"` or `"asked"`; a record with no answer is asked at first connect, and `evda_filing` records the reply. `evda_write`'s description leads with when to call it, because a deferred tool in the Claude app shows only that first line. One conversation is one `## HH:MM` section of the day. With "everything", Claude Code also gets a UserPromptSubmit hook, `.claude/hooks/evda-file-prompt.mjs`, that files each message verbatim as it is sent. `evda gather scan <conversations.json> --into <record>` reads a Claude.ai or ChatGPT export and, on apply, adds the owner's own messages the record lacks under each conversation's date and time.
110
+
111
+ **Your agent writes down what it repeats.** When it notices itself doing or explaining the same process a second time, or making the same correction twice, it writes the process as a skill in your record, `.claude/skills/<name>/SKILL.md` (a name, when to use it, the steps), and tells you in one line. Claude Code loads that folder on its own; every other app reads it through `evda_skills`. A skill that goes wrong on a run is revised, and what it replaced is kept beside it. A skill is how the agent works: one that is a rule about your life (a threshold, a count, a streak) is refused. `evda doctor` checks every skill's name and description.
112
+
60
113
  **The organizer.** `evda organize` goes through what you left inward. It copies each dated capture, verbatim, into the daily file of its date, once, and appends a report to `reports/organize/<date>.md`: people a recent note mentions, imports to check, undated notes, notes under no role. It moves nothing. With `--with-ai` it hands the judgment to your own `claude -p`, with the skill and read-only EVÐA tools, and appends its answer to the report. `evda look-back` does the same for the week.
61
114
 
62
115
  **Routines.** Setup offers a morning organize and a weekly look back, each optional, and schedules nothing without a yes. `evda routine morning` prints what to put in a local routine in the Claude desktop app (Code tab, then Routines, then New routine, then Local). `evda routine morning --install` writes and loads a launchd job instead, on a Mac. A cloud routine cannot read local files, so it cannot reach a record.
63
116
 
117
+ ## Presets
118
+
119
+ How a record is organized comes from a library, so an agent proposes a folder that already exists in it instead of inventing one. Each preset is `presets/<id>/preset.json`: an `id`, a `title`, `for` (who it suits), `folders` (each a path, and for a typed folder its `type`, `connectors` and `views`, validated by the same code as `folder.evda.json`), optional `circles` (proposed as proposal files, never created), optional `routines` (offered, never scheduled), and `mapping`, the folders that fill the four roles. Every folder a preset makes fills a role, and a preset that has one filling none fails its test. Two ship: `projects-and-areas` (numbered folders for projects, areas with courses under Academics, resources, work, captures, the daily journal and attachments) and `journal`. A course is a collection, so there is no student preset, and there is no archive folder: finished is a status. Setup offers them after purpose, with "none, start plain". Applying one adds the role paths the record lacks to `evda.json`; a role key the record already uses keeps its path, and the preset's folder fills the same role under a facet key named for it.
120
+
121
+ evda preset list
122
+ evda preset show <id>
123
+ evda preset apply <id> [--dry] [dir]
124
+ evda preset diff <id> [dir] what the preset has that this record does not
125
+
126
+ Applying only adds: missing directories are created and missing manifests written; a manifest that already says the same is skipped, one that says something else (or a file where a folder would go) is a `CONFLICT` that is left as it is, and nothing is moved, renamed or deleted. A second apply writes nothing. Exit 1 when there was a conflict. `test/presets.test.mjs` validates every shipped preset, so a malformed one fails a test rather than a person.
127
+
128
+ `evda doctor` reads folder manifests across the whole record root, not only under the record roles, skipping dot-directories and `node_modules` and not following symlinks.
129
+
64
130
  ## Circles and other people
65
131
 
66
132
  Everything is private until you share it. A circle is a part of the record you choose to share, plus who may read it. Audience and content are set separately: a public circle has the widest audience and the least content. Ask the agent to share something and it proposes a circle with a plain policy and waits for your yes; it never creates one, adds a reader, or moves an entry on its own. Another person reads a circle through a grant naming their own record (`evda grant family --to sam.atlas --kind person`), and `evda revoke` takes it back. A part can be more private than its circle, never less.
@@ -100,6 +166,16 @@ The training instructions in the scaffolded README and in setup come from one ta
100
166
 
101
167
  The tree above is what the scaffolder creates and not a requirement. `evda.json` carries a `mapping` from roles to paths, and every tool reads roles. An existing folder of notes becomes an EVÐA by adding `evda.json` with a mapping that names where things already are, and nothing moves.
102
168
 
169
+ ### Four roles, and records inside records
170
+
171
+ Every record at any scale has four roles in its `mapping` (Spec 07 section 2): `journal` (what happened, dated), `work` (efforts with a status and a date), `collections` (one folder per thing) and `knowledge` (what is true now). A role fills one or more folders: its own key and any `<role>/<facet>` key, so `journal`, `journal/captures` and `journal/dreams` are three journal folders. The keys named before the roles count toward them: `record/daily` and `record/captures` are journal, `record/people` is collections, `ledger` is knowledge. Every value stays a string, so a reader that knows only string mappings still opens the record. `work` may name a live source instead of a folder: `harlequin:` takes every board project whose `dev_projects.vault_path` lies in this record and not in one of its sub-records, `harlequin:<project>` names one, and `{ "source": "harlequin", "project": "<id>" }` is the same as an object. `evda doctor` fails a role over a missing folder, a file, one folder in two roles, a folder inside a sub-record, and a source it cannot read.
172
+
173
+ evda work [dir] [--env-file F] [--json]
174
+
175
+ reads the efforts, from the board (read only, with `SUPABASE_URL` and `SUPABASE_SERVICE_ROLE_KEY` from the environment or the env file) or from a folder of one file per effort whose frontmatter carries `status` and, optionally, `planned_for`. It prints `CHECKED <n> efforts`, or `SKIPPED` with why when there are no credentials, the board is unreachable or nothing is there; an effort with no status fails. Doctor checks a work folder offline and never calls the board.
176
+
177
+ An `evda.json` anywhere below the root starts a sub-record, with no depth limit. `evda doctor` walks each one as its own record, indented, and a sub-record that fails fails its parent. A record that declares `"subrecords": "bounded"` stops its circles, coverage, scan, releases and `evda circles check` at every sub-record, and reaches a sub-record's files only through a circle it mounts; a circle member inside a sub-record fails. A new scaffold is bounded. A record adopted before the roles is not until its owner declares it, so its circles keep covering the files it already syncs.
178
+
103
179
  ## The CLI
104
180
 
105
181
  evda doctor [dir] validate, and say what was examined
@@ -122,6 +198,8 @@ The tree above is what the scaffolder creates and not a requirement. `evda.json`
122
198
  evda revoke <circle> --to <record-id>
123
199
  evda access <circle> --as <record-id>
124
200
  may that record read the circle? exit 0 or 2, with why
201
+ evda publish public [dir] --out <dir> --key <seed file>
202
+ the public circle as a signed export
125
203
  evda status [dir] one screen
126
204
  evda where which record the locator resolves to, and by which rule
127
205
  evda use <dir> point ~/.evda/current at a record
@@ -129,11 +207,16 @@ The tree above is what the scaffolder creates and not a requirement. `evda.json`
129
207
  evda connect [dir] the MCP setup for each client, with this record's path
130
208
  evda skill install [--project <dir>]
131
209
  install the evda skill for Claude Code
210
+ evda hook install [dir] the keep-record Stop hook and the read guard, in the record's .claude/settings.json,
211
+ and the prompt hook that files each message when "filing" is "everything"
212
+ evda hook status [dir] whether each is installed and current
132
213
  evda organize [dir] [--dry-run] [--with-ai] [--model M]
133
214
  file captures into their day and report what belongs where; moves nothing
134
215
  evda look-back [dir] the week, read back by your own claude -p, appended to a report
135
216
  evda routine <morning|weekly> [dir] [--launchd] [--install]
136
217
  a Claude desktop routine, or a launchd job with --install
218
+ evda preset list | show <id> | apply <id> [--dry] [dir] | diff <id> [dir]
219
+ organize the record from the preset library; apply only adds
137
220
 
138
221
  The record is found through the locator: a directory argument, then `$EVDA_HOME`, then the nearest ancestor of the working directory holding `evda.json`, then `~/.evda/current`. Nothing assumes it was launched inside one.
139
222
 
@@ -144,10 +227,10 @@ The record is found through the locator: a directory argument, then `$EVDA_HOME`
144
227
  A circle is a subdirectory of the `circles` role holding `eco.yaml`, the substrate's eco manifest. The manifest declares it; a directory without one is not a circle and `evda doctor` fails on it.
145
228
 
146
229
  ```yaml
147
- id: ecos/public
230
+ id: ecos/c3f9a1d27b04e8c6519d2f7a0be4c8130
148
231
  kind: eco
149
232
  schemaVersion: "0.1"
150
- namespace: public.eco
233
+ namespace: c3f9a1d27b04e8c6519d2f7a0be4c8130.eco
151
234
  title: Public
152
235
  description: Anyone may read this circle. It holds what Dana publishes on purpose.
153
236
  public: true
@@ -171,7 +254,9 @@ policy:
171
254
  status: live
172
255
  ```
173
256
 
174
- The first six keys are the substrate's, and `id` and `namespace` follow from the directory name so the three cannot disagree. `maintainers` are the holders. `members` is the mapping principle one level down: each member names where the circle's bytes already live, relative to the record root, and nothing moves. A `path` member must exist on disk. A `table` member names rows on a host selected by equality, and is allowed only in a public circle, because a private circle's host may not read it. `public: true` is the whole of what makes a circle public; the reader takes the same path and needs no key. Reading an encrypted circle is not built; a private circle is validated for shape and never read.
257
+ The first six keys are the substrate's. `id` and `namespace` name one opaque eco id, minted at random when the circle is created and never derived from the directory name: the name stays on the owner's devices and the id is what travels (Spec 08, ruled 2026-09-17). An id still derived from the name is read, with a warning. `maintainers` are the holders. `members` is the mapping principle one level down: each member names where the circle's bytes already live, relative to the record root, and nothing moves. A `path` member must exist on disk. A `table` member names rows on a host selected by equality, and is allowed only in a public circle, because a private circle's host may not read it. `public: true` is the whole of what makes a circle public; the reader takes the same path and needs no key. A private circle's files stay plain on the owner's devices; what leaves a device is sealed to the circle's key, so a device holding no grant on it can neither receive nor open it (`lib/filechanges.mjs`, and the two-device test in `atlas-local/src/slice.e2e.test.ts`). `evda publish public --out <dir> --key <seed file>` writes the public circle as a signed plaintext export and refuses, exit 2, on a path another circle covers or a private circle's name or path in the bytes.
258
+
259
+ A `render` member, public circle only, is a file the export carries that the record does not hold (HQ-1351): `{ render: { view: projects, path: site/projects.json } }` is rendered at publish from every released entry whose frontmatter says `view: projects`, sorted by `order`, each entry's item taken from the one ```` ```json ```` block in its body. The default shape is a list of the items; `shape: object` holds exactly one entry and renders its item alone. So a fact lives once, placed by its subject and marked `share: public`, and the file the site reads is generated from it. The manifest lists a rendered file with `by: "view"` and the source entries' paths and sha256s. A rendered path is never also a path member, an entry naming a view no member renders refuses the publish, and `evda doctor` prints one line per rendered view saying how many entries it drew from, then the entries.
175
260
 
176
261
  `policy` is a list of rules, and a rule behaves like a test: one line in the owner's words, the date, the correction that made it (verbatim, quoted), an example that passes, one that fails, a check written so it could come back false, and a status of `live`, `revised` or `retired`. A rule is never edited in place; a revision is a new rule with `revisedBy` written on the old one. A number in a rule line is warned about: the check may count, the rule may not.
177
262