create-evda 0.1.5 → 0.1.7

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 (60) hide show
  1. package/CHANGELOG.md +114 -0
  2. package/README.md +74 -7
  3. package/bin/evda.mjs +427 -9
  4. package/create-evda.mjs +64 -16
  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 +346 -13
  15. package/lib/filechanges.mjs +622 -0
  16. package/lib/folders.mjs +1 -1
  17. package/lib/gather-apply.mjs +640 -0
  18. package/lib/gather.mjs +858 -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 +456 -36
  29. package/lib/messages.mjs +205 -0
  30. package/lib/migrate-people.mjs +231 -0
  31. package/lib/organize.mjs +176 -32
  32. package/lib/parity.mjs +184 -0
  33. package/lib/presets.mjs +58 -7
  34. package/lib/prompt-hook.mjs +88 -0
  35. package/lib/publish.mjs +264 -0
  36. package/lib/readers.mjs +319 -0
  37. package/lib/records.mjs +52 -0
  38. package/lib/references.mjs +5 -51
  39. package/lib/render.mjs +158 -0
  40. package/lib/roles.mjs +106 -1
  41. package/lib/routines.mjs +142 -18
  42. package/lib/secret-shape.mjs +58 -0
  43. package/lib/setup.mjs +124 -4
  44. package/lib/skills.mjs +266 -0
  45. package/lib/subrecord.mjs +121 -0
  46. package/lib/sync-rules.mjs +93 -0
  47. package/lib/tools.mjs +133 -27
  48. package/lib/update-check.mjs +146 -0
  49. package/lib/work.mjs +180 -0
  50. package/lib/yaml.mjs +117 -42
  51. package/package.json +25 -15
  52. package/presets/journal/preset.json +9 -1
  53. package/presets/projects-and-areas/preset.json +16 -9
  54. package/skills/evda/SKILL.md +67 -8
  55. package/templates/AGENTS.md +122 -14
  56. package/templates/README.md +15 -1
  57. package/templates/circles-README.md +3 -3
  58. package/templates/evda-digest.md +31 -6
  59. package/LICENSE +0 -21
  60. package/presets/student/preset.json +0 -13
package/CHANGELOG.md ADDED
@@ -0,0 +1,114 @@
1
+ # Changelog
2
+
3
+ Plain-English notes on how Iris behaves differently after each version. Not a commit log.
4
+
5
+ ## Unreleased
6
+
7
+ Organizing is on from the start. Setup installs the morning organize on a Mac (a launchd job that
8
+ runs your own Claude each morning at 8:00, or when the computer wakes), says so in one line, and
9
+ offers off: answer no during setup, pass `--no-routines`, or later run `evda routine morning
10
+ --uninstall`. The weekly look back is still offered, not on. When your AI's part of a routine cannot
11
+ run, the report now says why in words you can act on (Claude is not signed in on this computer: open
12
+ Claude and sign in), and the filing part still runs.
13
+
14
+ Your agent can message you. `evda_message` (and `evda message`) writes one new file in your record's
15
+ `messages/` folder, which the EVÐA phone app shows as a card, and your reply comes back as a file beside
16
+ it. `evda_replies` (and `evda replies`) hands your agent each reply once at the start of its next run,
17
+ and again if you change it. A new record has the folder; an older one gets it the first time a message
18
+ is sent, and `evda.json` can map it elsewhere. A message refuses anything shaped like a password, and a
19
+ reply you seal or just note is not shown to your agent.
20
+
21
+ A note you asked to have just noted, or a sealed one, stays that way wherever EVDA copies it.
22
+ `evda organize` no longer copies a just-noted capture into its day: the day gets one line saying where
23
+ it is, and once you release it the next organize files its words. Gathering a pile quotes nothing of a
24
+ just-noted file and never asks your AI about it, and the copy it places keeps the flag. Turning a
25
+ person's page into a typed profile never lifts a heading or a quote out of a sealed part. Sync never
26
+ sends a just-noted or sealed note to anyone else's devices because of a `share:` mark.
27
+
28
+ Anything can be sealed: `sealed: true` in a note's frontmatter, or a part of a note fenced as
29
+ ` ```sealed `. Nothing but your own devices opens a sealed note or part, ever. Your agent is never
30
+ shown it or told where it is, whichever AI it is, and no tool lets it unseal one; you unseal by
31
+ editing the file. Publishing leaves a sealed part out of the file it sits in and refuses a sealed
32
+ note outright, `evda doctor` fails a sealed note that carries `share:`, and `evda search` on your own
33
+ device still finds everything, marked `[sealed]`.
34
+
35
+ A hand-written `|` or `>` block in a frontmatter or `eco.yaml` now reads the way every other YAML
36
+ tool reads it: a line starting with `#` inside it (a markdown heading in a description) stays, and
37
+ so do leading blank lines, `|+` trailing newlines and more-indented lines under `>`. Indentation
38
+ indicators such as `|2` are read instead of refused.
39
+
40
+ `evda doctor` no longer reports a person's dated section as missing its observation when the
41
+ observation is worded differently from the heading. An observation dated the same day covers it, one
42
+ observation per section, so a section with none still fails.
43
+
44
+ Setup asks one thing about filing: should your agent file everything you say automatically, or only
45
+ when you ask? Everything is the default. The answer goes in `evda.json` as `"filing"`, and a record
46
+ with no answer gets the question the first time an app connects. In the Claude app, the filing
47
+ instruction now leads each tool's description, which is what the app actually reads, and the
48
+ operating layer opens with five lines for a chat app. One conversation is one `## HH:MM` section of
49
+ the day, not a heading per message. In Claude Code, an owner who chose everything gets a hook that
50
+ files each message as they send it. And `evda gather` takes a Claude.ai or ChatGPT data export
51
+ (`conversations.json`) and adds the messages you wrote there that your record does not already hold,
52
+ under each conversation's date and time, never the model's replies.
53
+
54
+ Your agent says who reads each part of your EVÐA. Setup writes the AI you chose as the reader of
55
+ the whole record, and a circle can name another one, a model on your own computer, or none;
56
+ `evda doctor` prints it under "Read by". Say "just note this" and it is kept where no AI reads it
57
+ until you say it can. When something is held back, your agent says what is there and how you open
58
+ it. The README quotes what each AI company's own pages say about training and retention, with the
59
+ date they were read, and explains how to run a model locally.
60
+
61
+ Iris files what you say without being asked. In Claude Code a Stop hook, installed into the
62
+ record when you pick Claude at setup (or with `evda hook install`), asks once before a session
63
+ ends having read the record or heard you out and filed nothing. In the Claude desktop app and
64
+ ChatGPT, the MCP server adds one line to its results until something is filed. People, projects
65
+ and places with an entry get a dated section when they come up; one without an entry is offered,
66
+ never created.
67
+
68
+ Your EVÐA can reach the Claude phone app. `evda mcp --http` serves the same tools over HTTPS
69
+ through a tunnel you run, and nothing connects until you type a one-time owner code, printed by
70
+ `evda mcp token --new` on the machine that holds the record, into the page Claude opens. The
71
+ connection reads as Claude, so parts of the record you set to be read by another AI stay closed to
72
+ it. `evda mcp token --revoke-all` ends every connection at once.
73
+
74
+ Iris writes down what it repeats. A process done or explained a second time becomes a skill in your
75
+ record, `.claude/skills/<name>/SKILL.md`, and Iris tells you in one line; any app reads it with
76
+ `evda_skills`. It is never a rule about your life. Iris can make an EVÐA inside yours (a project, a
77
+ company, an agent) and tells you what doctor said about it; your own `evda.json` changes only when
78
+ you say yes to its circles stopping there. The day's entry holds your words and one line on what the
79
+ conversation was about, marked as not yours. `evda hook install` and setup now install the read guard
80
+ with the Stop hook, and `evda doctor` says whether each is there.
81
+
82
+ ## 0.1.5
83
+
84
+ Presets: pick a way to organize the record (numbered inbox, projects and areas, or a student
85
+ layout) from a small reviewed library, applied only by adding folders. Nothing already there is
86
+ touched or overwritten.
87
+
88
+ ## 0.1.4
89
+
90
+ Iris can now run through an MCP server, so Claude Code, Codex and the Claude desktop app read
91
+ and write the record without you copying files anywhere. `evda skill install` adds a matching
92
+ Claude Code skill. Captures can be filed into the right day automatically (`evda organize`), and
93
+ the week can be read back for you (`evda look-back`).
94
+
95
+ ## 0.1.3
96
+
97
+ Removed a claim that never worked: pasting AGENTS.md into a ChatGPT or Claude Project's
98
+ instructions field does not run an EVÐA, because that field forgets everything after one
99
+ conversation. Setup now offers a one-time import into a real coding-agent record instead.
100
+
101
+ ## 0.1.2
102
+
103
+ Setup asks one question at a time instead of a wall of prompts, and does not finish until you
104
+ confirm your AI's training setting is off, with a link to where that setting actually lives.
105
+
106
+ ## 0.1.1
107
+
108
+ Added a plain README written for the person who just ran `create-evda`, not for the agent:
109
+ how Iris responds, how it improves from your corrections, and how you improve alongside it.
110
+
111
+ ## 0.1.0
112
+
113
+ First publish. The record itself: a manifest, AGENTS.md as the operating layer, the hypothesis
114
+ 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
 
@@ -33,13 +41,41 @@ 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
@@ -47,9 +83,17 @@ Setup ends by asking whether to bring in what an AI you already talk to knows ab
47
83
  evda_presets the preset library, or one preset's folders
48
84
  evda_propose_structure what a preset would add to this record, in plain words. Writes nothing
49
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
50
93
  evda_doctor evda doctor, as a report
94
+ evda_check_update whether newer EVDA tooling exists. The only tool that reaches the network
51
95
 
52
- 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:
53
97
 
54
98
  ```bash
55
99
  claude mcp add --scope user evda -- /path/to/node /path/to/evda.mjs mcp ~/my-evda # Claude Code
@@ -60,13 +104,19 @@ For the Claude desktop app, add the same command under `mcpServers` in `claude_d
60
104
 
61
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.
62
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
+
63
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.
64
114
 
65
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.
66
116
 
67
117
  ## Presets
68
118
 
69
- 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) and optional `routines` (offered, never scheduled). Three ship: `projects-and-areas` (numbered top folders for inbox, projects, areas, resources, archive, captures, metadata and attachments), `journal`, and `student`. Setup offers them after purpose, with "none, start plain".
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.
70
120
 
71
121
  evda preset list
72
122
  evda preset show <id>
@@ -116,6 +166,16 @@ The training instructions in the scaffolded README and in setup come from one ta
116
166
 
117
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.
118
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
+
119
179
  ## The CLI
120
180
 
121
181
  evda doctor [dir] validate, and say what was examined
@@ -138,6 +198,8 @@ The tree above is what the scaffolder creates and not a requirement. `evda.json`
138
198
  evda revoke <circle> --to <record-id>
139
199
  evda access <circle> --as <record-id>
140
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
141
203
  evda status [dir] one screen
142
204
  evda where which record the locator resolves to, and by which rule
143
205
  evda use <dir> point ~/.evda/current at a record
@@ -145,6 +207,9 @@ The tree above is what the scaffolder creates and not a requirement. `evda.json`
145
207
  evda connect [dir] the MCP setup for each client, with this record's path
146
208
  evda skill install [--project <dir>]
147
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
148
213
  evda organize [dir] [--dry-run] [--with-ai] [--model M]
149
214
  file captures into their day and report what belongs where; moves nothing
150
215
  evda look-back [dir] the week, read back by your own claude -p, appended to a report
@@ -162,10 +227,10 @@ The record is found through the locator: a directory argument, then `$EVDA_HOME`
162
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.
163
228
 
164
229
  ```yaml
165
- id: ecos/public
230
+ id: ecos/c3f9a1d27b04e8c6519d2f7a0be4c8130
166
231
  kind: eco
167
232
  schemaVersion: "0.1"
168
- namespace: public.eco
233
+ namespace: c3f9a1d27b04e8c6519d2f7a0be4c8130.eco
169
234
  title: Public
170
235
  description: Anyone may read this circle. It holds what Dana publishes on purpose.
171
236
  public: true
@@ -189,7 +254,9 @@ policy:
189
254
  status: live
190
255
  ```
191
256
 
192
- 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.
193
260
 
194
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.
195
262