create-evda 0.1.8 → 0.1.10

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/CHANGELOG.md +109 -1
  2. package/README.md +20 -7
  3. package/bin/evda.mjs +277 -7
  4. package/create-evda.mjs +17 -4
  5. package/dist/pairing.mjs +2932 -1684
  6. package/hooks/evda-day-writer-guard.mjs +7 -0
  7. package/lib/acknowledge.mjs +187 -0
  8. package/lib/adopt.mjs +488 -0
  9. package/lib/agents.mjs +1 -1
  10. package/lib/attested-host.mjs +269 -0
  11. package/lib/browse.mjs +354 -0
  12. package/lib/circles.mjs +5 -1
  13. package/lib/clients.mjs +29 -2
  14. package/lib/connect.mjs +9 -2
  15. package/lib/connecting-apps.mjs +56 -0
  16. package/lib/connector-tools.mjs +85 -0
  17. package/lib/corrections.mjs +34 -0
  18. package/lib/credentials-migrate.mjs +120 -0
  19. package/lib/day-file.mjs +173 -15
  20. package/lib/day-writer.mjs +110 -0
  21. package/lib/doctor.mjs +45 -3
  22. package/lib/every-chat.mjs +128 -0
  23. package/lib/filechanges.mjs +203 -68
  24. package/lib/gather-apply.mjs +176 -26
  25. package/lib/gather.mjs +119 -17
  26. package/lib/html-notes.mjs +124 -0
  27. package/lib/keep-hook.mjs +61 -8
  28. package/lib/keychain.mjs +181 -0
  29. package/lib/manifest.mjs +5 -1
  30. package/lib/mcp-auth.mjs +41 -1
  31. package/lib/mcp-http.mjs +42 -4
  32. package/lib/mcp.mjs +1198 -76
  33. package/lib/measurement-log.mjs +249 -0
  34. package/lib/messages.mjs +5 -2
  35. package/lib/migrate-people.mjs +54 -20
  36. package/lib/pairing.mjs +243 -5
  37. package/lib/parity.mjs +47 -13
  38. package/lib/person-folders.mjs +89 -0
  39. package/lib/plugin-hook.mjs +109 -0
  40. package/lib/plugin.mjs +208 -0
  41. package/lib/presets.mjs +26 -5
  42. package/lib/publish.mjs +55 -10
  43. package/lib/qr.mjs +317 -0
  44. package/lib/record.mjs +74 -0
  45. package/lib/routines.mjs +54 -4
  46. package/lib/sigstore-trust.json +20 -0
  47. package/lib/skills.mjs +1 -1
  48. package/lib/sync-lock.mjs +143 -0
  49. package/lib/sync-rules.mjs +154 -1
  50. package/lib/takeout.mjs +169 -0
  51. package/lib/tdx-attestation.mjs +412 -0
  52. package/lib/tdx-trust.json +10 -0
  53. package/lib/tools.mjs +1040 -31
  54. package/lib/touches.mjs +427 -0
  55. package/lib/update-check.mjs +30 -0
  56. package/lib/watch.mjs +160 -0
  57. package/lib/yaml.mjs +8 -4
  58. package/package.json +2 -1
  59. package/skills/evda/SKILL.md +14 -0
  60. package/templates/AGENTS.md +81 -10
  61. package/templates/evda-digest.md +5 -1
package/CHANGELOG.md CHANGED
@@ -4,15 +4,123 @@ Plain-English notes on how Iris behaves differently after each version. Not a co
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ When a filing names pages your EVÐA already has (a person, a project, a topic) or open tickets on your
8
+ board, and the conversation adds to none of them, Iris is now asked once, naming them, whether what you said adds to one; adding
9
+ nothing is a fine answer. In Claude Code the record's Stop hook asks before the session stops, and in
10
+ the chat apps the next tool result asks. A record with the Stop hook installed shows it as older in
11
+ `evda doctor` until `evda hook install` refreshes it.
12
+
13
+ Claude Cowork can reach your EVÐA now. Cowork does not start the servers in the desktop app's
14
+ config and does not read your folder's hooks, so `evda plugin` builds a plugin for your record (its
15
+ evda tools, the hooks that keep it, and a skill that has Iris read the operating layer first), and
16
+ you upload the zip in Customize, then Plugins, then Upload plugin. `create-evda` and `evda connect`
17
+ print the command. The plugin's hooks act only in Cowork, so the same plugin syncing into Claude Code
18
+ files nothing twice.
19
+
20
+ `evda secret migrate` moves the passwords in Credentials/ files sealed before they went to the
21
+ Keychain: each value goes into the Keychain, and the file keeps a pointer in its place, the same as a
22
+ new gather does. A file whose Keychain write fails stays exactly as it was, an item already in the
23
+ Keychain is never overwritten, and running it again changes nothing. `--dry` says what it would move.
24
+ Two lines with the same label in one file (two "Password:" lines) now get separate Keychain items,
25
+ where before the second overwrote the first.
26
+
27
+ The EVÐA app's setup now asks how to organize your EVÐA right after what you want it for, offering
28
+ the same presets as `create-evda`, or starting plain. `evda preset list --json` prints the list it
29
+ reads.
30
+
31
+ `create-evda --help`, `create-evda -h`, `evda init --help` and `evda mcp --help` now print how to use
32
+ them and stop. Before, `create-evda -h` made a folder named `-h` and `evda mcp --help` started serving
33
+ your record. On a Mac, `create-evda` now says it is installing the daily morning organize as a
34
+ launchd job before it does, with `--yes` too, and names `--no-routines` to skip it. Gathering a pile
35
+ now skips what apps leave behind (Office lock files, empty files, a Recently Deleted folder, Google
36
+ Takeout's `archive_browser.html`) and lists each one, with why, in the proposal.
37
+
38
+ `evda publish public` now leaves a markdown file's `sources:` frontmatter out of what it exports. That
39
+ field lists the private files a public page was written from, so it never belonged in public, and it
40
+ was making the publish refuse every run once a page carried one. A private path in a page's body
41
+ still refuses the publish exactly as before.
42
+
43
+ When Iris files something, it is now told which pages you already have that the words name (a person,
44
+ a topic, a project) and which shared circles that reaches, such as a public entry derived from the
45
+ folder it just wrote to. It is information for Iris to judge, so it still decides what to write, and
46
+ nothing noted, sealed, or set for a different AI is ever named.
47
+
48
+ When your work lives on a board (`"work": "harlequin:"`), filing also names the open tickets the
49
+ words reference, by `HQ-` number or by a distinctive run of a ticket's title, at most five, so a
50
+ conversation about a ticket's subject points Iris at the ticket. A done or obsolete ticket is never
51
+ named. The board is read in the background with the same credentials as `evda work` (or the env file
52
+ `EVDA_WORK_ENV_FILE` names), so a slow or unreachable board never slows a filing.
53
+
54
+ A people folder now keeps one file per person, and `evda doctor` says so when it does not: a folder
55
+ inside it, a name with a parenthetical when nobody else shares the name, and a stub that only
56
+ points at another page each fail, and so does a page with no person-profile frontmatter, which
57
+ doctor cannot read. Gathering a pile writes every page it puts in a people folder as a profile, and
58
+ migrating people now types a page with no dated section (its one observation is the day it was
59
+ typed) and a page that already has frontmatter, keeping what that frontmatter says. Applying a preset that makes a people folder also makes `Processing/` beside it
60
+ for the docs where you work something through, and a README in the folder saying the rule.
61
+
62
+ In the Claude app, Iris starts a chat knowing what your last days were about, not only when you
63
+ wrote: each recent entry comes with its one line of context and the opening of your words, and the
64
+ people whose pages gained a dated section this week are listed with those sections. Searching your
65
+ record shows the most recent matches first. Iris answers you in the reply itself and says what it
66
+ filed in one line after, instead of writing its answer into a page. And the Claude app now reads
67
+ your whole instructions file at the start of a chat, up to about 100,000 characters, where it used
68
+ to get some sections as a heading to fetch. Noted and sealed entries still never appear.
69
+
70
+ In a chat app, Iris now writes where it writes from a terminal. A correction you give it lands in
71
+ the file you keep corrections in, when `evda.json` names it as `"corrections"`, as a dated section
72
+ in your words; before, a record without a "What I have been taught" heading lost every one. Iris can
73
+ add a row to a log kept as a table (a food log, a spike log, a weekends board) with
74
+ `evda_append_row`, and put a new section inside the part of a file it belongs in with
75
+ `evda_append`'s `under`, so a queued idea no longer lands under "Completed". When Iris offers to
76
+ start a page, a person's page or a folder and you say yes, `evda_create` makes it, and never where
77
+ something already is.
78
+
79
+ When two of your machines share one record through iCloud, one of them can be the only one that
80
+ writes the daily note. Set EVDA_DAY_WRITER on every other machine and add hooks/evda-day-writer-guard.mjs
81
+ to that machine's own Claude Code settings: an agent there that tries to write the note directly is
82
+ stopped and told to file through evda_write on the writing machine, because two machines writing the
83
+ same note within seconds lose one of the writes with no conflict copy.
84
+
85
+ The first time you talk to your EVÐA from a chat app (Claude, ChatGPT, or any other), Iris gives
86
+ you one line to add to that app's every-chat instructions, and says where that setting is. With it
87
+ there, every chat starts as Iris, even one that never opens your record. Tell Iris it is set, or
88
+ that you don't want it, and that app never asks again; a second app asks once for itself. If you
89
+ file only when you ask, the line loads Iris and asks for nothing more. `create-evda` and `evda
90
+ connect` print the same line.
91
+
92
+ The EVÐA app is one sidebar and the page you are reading. Today's Journal is first, there even
93
+ before you have written today, and what you type at the end of it is added to today's note,
94
+ verbatim, the way your AI's evda_write does. Below it, Journal, Captures, People and your project,
95
+ area and knowledge folders are pinned from your mapping, then Instructions (CLAUDE.md, AGENTS.md,
96
+ evda.json and any file the agents block is written into), then every folder of the record. Devices,
97
+ Connect your AI and Switch EVÐA sit quietly at the foot. A file's circle shows only when it is not
98
+ your record's usual one, and markdown reads formatted. Entries you noted or sealed, and parts you
99
+ set so no AI reads, stay closed. Tooling (dot-files, lockfiles, scripts, licenses, backups, empty
100
+ files) is left out, with one line per folder counting it. The window drags by its top edge. Large
101
+ files open whole: `evda browse` and `evda capture` wait for their answer to reach the app before
102
+ exiting, where before a file past 64 KB arrived cut off.
103
+
7
104
  Your phone can join your EVÐA. `evda pair` on the computer your record is on shows a one-time code
8
105
  and a QR link; it works once, for 10 minutes, and the phone gets only the parts you name (the
9
106
  journal by default). `evda sync` adds the phone once it has used the code, takes in what it wrote,
10
107
  and sends what changed; a note written on the phone lands under the day, in your words. `evda
11
108
  devices` lists what is paired and `evda remove <device>` removes one: it adds nothing more and
12
- receives nothing new. You can also ask your AI to pair a phone (`evda_pair_device`). Pairing goes
109
+ receives nothing new. You can also ask your AI to do all of it (`evda_pair`, `evda_devices`, `evda_sync_status`,
110
+ `evda_remove_device`): it shows a QR code to scan, adds the phone on its own once it scans, says
111
+ when each device was last heard from and what is still on its way to it, and removes a device only
112
+ after you say yes to what removing does. A phone paired this way pairs to the computer the AI's
113
+ EVÐA server runs on, and the answer names that computer. A second computer of yours (Hestia) speaks
114
+ as its own device and never as the laptop: until a grant makes it owner of a part it refuses to
115
+ pair, and once it owns one it pairs a phone to itself. Pairing goes
13
116
  through a relay that cannot read what it carries, and needs Node 22.13 or newer; everything else
14
117
  still runs on Node 20.
15
118
 
119
+ One sync of a record runs at a time. The Mac app syncing on its own, a launchd job and `evda sync`
120
+ at a terminal wait for each other; if a sync is still running after twenty seconds, the second says
121
+ "A sync of this EVÐA is already running. Try again in a moment." and changes nothing. A sync that
122
+ crashed leaves nothing in the way: the next one sees the process is gone and goes ahead.
123
+
16
124
  Organizing is on from the start. Setup installs the morning organize on a Mac (a launchd job that
17
125
  runs your own Claude each morning at 8:00, or when the computer wakes), says so in one line, and
18
126
  offers off: answer no during setup, pass `--no-routines`, or later run `evda routine morning
package/README.md CHANGED
@@ -76,6 +76,7 @@ apply places only what is new, in the record's own folders.
76
76
  evda_operating_layer AGENTS.md, read first every session
77
77
  evda_recent the last few days of the record
78
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
79
+ evda_record_correction one dated line appended to AGENTS.md's "What I have been taught", outside the installer's block. Never edits an earlier entry
79
80
  evda_import what another AI said about you, filed under record/imports with its source and date
80
81
  evda_search plain text search inside the record, on this machine
81
82
  evda_circles your circles and their policies
@@ -91,9 +92,12 @@ apply places only what is new, in the record's own folders.
91
92
  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
93
  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
93
94
  evda_doctor evda doctor, as a report
94
- evda_pair_device a one-time code and QR link for your phone, and what to do on it; the phone gets only the parts named
95
+ evda_pair a one-time code and a QR code to scan for your phone, paired to the computer this server runs on; the phone gets only the parts named, and is added on its own once it uses the code
96
+ evda_finish_pairing waits, at most two minutes, for the phone to use its code, and says when it is in
95
97
  evda_sync_devices adds a phone that used its code, takes in what your devices wrote, sends what changed
96
- evda_devices the devices paired with your EVÐA and what each reads
98
+ evda_devices the devices paired with your EVÐA on this computer, what each reads, and when it was last heard from
99
+ evda_sync_status per device what is waiting, sent and confirmed, and whether a sync is running. Reads only
100
+ evda_remove_device removes a device; without confirm: true it only says what removing would do, for your yes
97
101
  evda_check_update whether newer EVDA tooling exists
98
102
 
99
103
  Every write appends, refuses anything shaped like a password, key or token, and says the path it wrote. Two kinds of call leave this machine. `evda_check_update` asks 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. The device tools talk to the relay that carries your EVÐA between your own devices, and everything they send is sealed here first: the relay cannot read it. `evda connect` prints the setup for your record, with its path filled in:
@@ -103,11 +107,18 @@ claude mcp add --scope user evda -- /path/to/node /path/to/evda.mjs mcp ~/my-evd
103
107
  codex mcp add evda -- /path/to/node /path/to/evda.mjs mcp ~/my-evda # Codex
104
108
  ```
105
109
 
106
- For the Claude desktop app, add the same command under `mcpServers` in `claude_desktop_config.json` (Settings, then Developer, then Edit Config) and restart the app. `create-evda` prints all three at the end of setup.
110
+ **One layer, sized per app.** `evda_operating_layer` serves the core and AGENTS.md to every app, but a section that only makes sense with a shell (scripts to run, hosts to ssh to, local MCP servers) is noise in a chat app. Put `<!-- evda:surface terminal -->` on the line right after a `## ` heading and that section, with its subsections, goes only to coding agents (Claude Code, Codex). Every other app, including one the server has never heard of, gets the rest, in as few parts as its tool result limit allows, and is told which sections were left out. A record with no marker reads the same everywhere. The server knows the app by `initialize`'s `clientInfo` name, and the remote server logs that name and version, nothing else of it.
111
+
112
+ **Each surface reaches a record its own way.** `create-evda` and `evda connect` print every one of these with your record's path filled in.
113
+
114
+ - **Claude Code** (terminal, IDE, the desktop app's Code tab): `claude mcp add` above for every folder, and in sessions opened in the record its own `.claude/settings.json` hooks and `.claude/skills/` load on their own.
115
+ - **The Claude desktop app's chat**: add the same command under `mcpServers` in `claude_desktop_config.json` (Settings, then Developer, then Edit Config) and restart the app. That file reaches only the chat: Cowork does not start its servers.
116
+ - **Claude Cowork**: `evda plugin <dir>` builds a plugin for this one record, a folder and a zip under `.evda/plugin/` (or `--out <zip>`), and the upload is the one step left to you: in the Claude app, Customize, then Plugins, then Add, then Upload plugin, and choose the zip. Cowork reads no folder's `CLAUDE.md`, `AGENTS.md` or hooks, so the plugin carries all three ways in: the record's MCP server (`evda mcp <dir>`, the path baked in, because Cowork does not ask for plugin settings), a skill that loads the operating layer before the first reply, and hooks that run the record's own keep-record hook, prompt-filing hook (with "everything") and read guard, the files `evda hook install` keeps current. It works in Cowork tasks that run on your computer. The plugin also loads in Claude Code sessions signed in to the same account; its hooks stay quiet there (they act only when Claude Code runs a Cowork task), and `claude plugin disable <name>@synced` takes it out of Claude Code. Move the folder and you build and upload it again.
117
+ - **claude.ai** (web and phone): no local server reaches it. `evda mcp --http` serves the record over HTTPS behind OAuth, through a tunnel, as a connector you add in Settings, then Connectors.
107
118
 
108
119
  **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.
109
120
 
110
- **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.
121
+ **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 Cowork the plugin from `evda plugin` runs the same hooks. In apps with no hooks (the Claude desktop app's chat, 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. A second check rides on both: a write's answer names the existing entries its words bear on, and a conversation that was named some and added to none of them is asked once, naming them (and any open board tickets it named), with adding nothing as a fine answer. It goes quiet after a write to one of them or once asked. The Stop hook reads those names back out of the Claude Code transcript and the MCP server keeps them per chat, so nothing about it is stored in your files.
111
122
 
112
123
  **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.
113
124
 
@@ -121,7 +132,7 @@ For the Claude desktop app, add the same command under `mcpServers` in `claude_d
121
132
 
122
133
  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.
123
134
 
124
- evda preset list
135
+ evda preset list [--json] --json: one line, [{id, title, for}], what the EVÐA app's setup offers
125
136
  evda preset show <id>
126
137
  evda preset apply <id> [--dry] [dir]
127
138
  evda preset diff <id> [dir] what the preset has that this record does not
@@ -163,11 +174,11 @@ Writes:
163
174
  grant file per reader and circle
164
175
  .evda/version the schema version actually on disk
165
176
  .evda/due.jsonl derived from the ledger's Due lines
166
- .evda/digest.md derived from the fenced block of AGENTS.md, under 4096 bytes
177
+ .evda/digest.md derived from the fenced block of AGENTS.md, under 6144 bytes
167
178
 
168
179
  The training instructions in the scaffolded README and in setup come from one table, `lib/setup.mjs`, with a link to each provider's page.
169
180
 
170
- 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.
181
+ 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. `evda adopt <dir>` writes that mapping: an Iris Vault (`00_Inbox` through `06_Metadata`) maps without a question, any other folder is placed by its name or named back to the owner to answer with `--map <folder>=<role>`, and it adds `AGENTS.md`, `.evda/`, the Claude Code hooks and one `@AGENTS.md` line at the end of the owner's `CLAUDE.md`. Every other file stays byte for byte, and `evda adopt --revert <manifest>` puts the folder back exactly as it was. A chat app runs it through `evda_adopt`, which writes nothing without `confirmed: true`.
171
182
 
172
183
  ### Four roles, and records inside records
173
184
 
@@ -208,6 +219,8 @@ An `evda.json` anywhere below the root starts a sub-record, with no depth limit.
208
219
  evda use <dir> point ~/.evda/current at a record
209
220
  evda mcp [dir] serve the record over MCP on stdio for Claude Code, Codex or the Claude app
210
221
  evda connect [dir] the MCP setup for each client, with this record's path
222
+ evda plugin [dir] [--out <zip>]
223
+ a Claude plugin for this record, for Cowork: its server, hooks and skill
211
224
  evda skill install [--project <dir>]
212
225
  install the evda skill for Claude Code
213
226
  evda hook install [dir] the keep-record Stop hook and the read guard, in the record's .claude/settings.json,