dreamteamer 0.30.0 → 0.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,14 +1,24 @@
1
1
  # dreamteamer
2
2
 
3
- **Structured, modular memory for coding agents.**
3
+ **dreamteamer is a modular AI workspace builder.**
4
4
 
5
- Your agent already has a memory. You just can't see it — it's prose, in a black box somewhere,
6
- untracked and unshared. And memory *is* context, which is the single biggest lever on what your agent
7
- decides and how well it does it. So the most consequential thing in your setup is the one you have the
8
- least access to.
5
+ It gives your coding agents a structured, modular memory. Instead of hiding context in unmanaged prose, dreamteamer stores memory as **plain markdown files with a schema** directly in your git repo. Agents read it natively, and you can browse it as tables, boards, and forms.
9
6
 
10
- dreamteamer makes it **files with a schema**: plain markdown in your git repo that your agent reads
11
- natively, and that you can browse as tables, boards and forms.
7
+ No server, no account, no telemetry. Just a lightweight npm package.
8
+
9
+ ---
10
+
11
+ ## Features
12
+
13
+ - **Structured Memory as Files**: A record is just a markdown file with YAML frontmatter. Your agent opens it like any other file.
14
+ - **Strict Validation**: Schemas ensure your agents use agreed-upon terminology. Invalid links, wrong types, or unknown fields are rejected before they touch the disk.
15
+ - **Agent Agnostic**: Author a skill or schema once, use it everywhere. Core compiles to Claude Code, Cursor, Gemini CLI, and more.
16
+ - **NPM Modularity**: Distribute domain knowledge, skills, and agents using the npm ecosystem you already know.
17
+ - **Visual Editor**: The [VS Code extension](https://github.com/dreamteamer/dreamteamer-vscode) gives you a powerful UI (tables, boards, forms) over your plain text files.
18
+
19
+ ## Getting Started
20
+
21
+ Scaffold your AI workspace in seconds:
12
22
 
13
23
  ```bash
14
24
  npm i dreamteamer
@@ -18,15 +28,10 @@ npx dreamteamer check # prove every record and every link is intact
18
28
  npx dreamteamer help # the full command surface
19
29
  ```
20
30
 
21
- Apache-2.0. No server, no account, no telemetry.
31
+ ## How It Works
22
32
 
23
- ## Structured
24
-
25
- A record is a file. That's the whole trick.
26
-
27
- ```
28
- data/meetings/2026/07/kickoff.meeting.md
29
- ```
33
+ ### 1. Define Records
34
+ A record is a file inside your collection directory (e.g., `data/meetings/2026/07/kickoff.meeting.md`):
30
35
 
31
36
  ```yaml
32
37
  ---
@@ -38,160 +43,49 @@ project: projects/apollo
38
43
  Ada walked through the constraints. Lin owns the spec by Friday.
39
44
  ```
40
45
 
41
- Your agent opens that file the way it opens any file. Nothing is intercepted, nothing is proxied,
42
- there is no API to learn.
43
-
44
- But `attendees` isn't a string — it's a link. `dreamteamer check` proves every one of them resolves,
45
- and renaming `contacts/ada` updates everything pointing at it. A write with an unknown field, a wrong
46
- type, or a reference to a record that doesn't exist is **rejected before it touches disk**.
47
-
48
- **A schema is an agreement about what things are called.** Shared terminology with guardrails — not a
49
- cage, because it stays negotiable. You change it by saying so:
50
-
51
- > *"From here on a client has a renewal date, and it's a date."*
52
-
53
- That's a schema update and a data migration, and it's an **explicit, reviewable event** rather than
54
- silent drift. Once it exists you get the column in a table, the field in a form, validation, sorting
55
- and aggregation — all of it falling out of having said what the thing is.
56
-
57
- The shape of a record is deliberately dull, because dull is what survives:
58
-
59
- - records are `<id>.<suffix>.<ext>` files; **the id is the path** inside the collection folder
60
- - references are `<collection>/<id>` — always qualified, greppable, never a bare name
61
- - a collection may be scoped under a **declared namespace** — `health/doctors/dana-levi`, stored in
62
- `data/health/doctors/`. The default namespace is the empty prefix, so `tasks/kickoff` is unchanged
63
- - a write lands on disk; `dreamteamer commit` publishes it, one commit per repo
64
- - schemas are JSON Schema in a YAML file, one per collection
65
-
66
- ### Machine-specific references
67
-
68
- Some things a record points at only exist on one machine — a synced Drive folder, an external disk,
69
- a checkout somewhere else. Those are written as **templates**, never as absolute paths:
70
-
71
- ```yaml
72
- source_file: ${env:FILES_FOLDER}/2026/q3.pdf
73
- ```
74
-
75
- Three variables, borrowing VS Code's grammar: `${env:NAME}` — declared in `dreamteamer.vars` in
76
- `package.json`, valued in the gitignored `.env` (an empty or whitespace-only value counts as no
77
- value at all) — plus `${workspaceFolder}` and `${userHome}`. One verb renders them:
46
+ ### 2. Enforce Schemas
47
+ Your agents read the file directly, but `dreamteamer check` ensures that every reference (like `contacts/ada`) actually resolves. **A schema is an agreement about what things are called.**
78
48
 
79
- ```bash
80
- npx dreamteamer resolve '${env:FILES_FOLDER}/x' # → /Volumes/annex/x
81
- npx dreamteamer resolve <collection>/<id> <field> # render what a record already holds
82
- ```
83
-
84
- **Templates are ordinary data — write them literally; nothing substitutes until `resolve` is
85
- called.** `get`, `list`, `check` and every harness see the template verbatim, which is exactly what
86
- makes the record mean the same thing on every machine instead of quietly meaning two things. An
87
- undeclared key and a declared-but-absent one are different errors, and `compile` warns — by name,
88
- never by value — when a declared var has nothing behind it here.
49
+ ### 3. Share & Compose
50
+ Because dreamteamer uses npm, you can install domain modules containing collections, skills, and agents. If a module doesn't perfectly fit your needs, you don't fork it—you adapt it locally by overriding just the schema fields you need to change.
89
51
 
90
- ## Modular
52
+ ## Programmatic Usage
91
53
 
92
- **Data and skills are the new app structure.** A coding agent with the right skills over the right
93
- data is arbitrary functionality — but composing that with no module system is where most setups stall.
54
+ Use dreamteamer in your own scripts or apps:
94
55
 
95
- So dreamteamer doesn't invent one. **It uses npm.**
56
+ ```javascript
57
+ import { openWorkspace, Store } from 'dreamteamer';
96
58
 
97
- `node_modules` is battle-tested, universally adopted, and already sitting in nearly every
98
- coding-agent setup. A module contributes collections, skills, agents, commands, command-bindings and
99
- UI views — and skills and agents are treated as exactly what they are: **memory that loads into
100
- context**, living in the same module structure as everything else, in a standard your tooling already
101
- understands.
59
+ const ws = await openWorkspace('.'); // no compile, no writes
60
+ const store = new Store(ws);
102
61
 
103
- Three channels, one shape:
104
-
105
- ```
106
- modules/<name>/ # lives in this repo
107
- git_modules/<name>/ # lives in its own repo
108
- node_modules/<name>/ # published package
62
+ for (const { id, fields } of store.readAll('notes')) {
63
+ console.log(id, fields.title);
64
+ }
109
65
  ```
110
66
 
111
- Precedence runs top to bottom, so a local copy shadows a published one — which is how you develop a
112
- module and use it in the same workspace at the same time.
113
-
114
- A published package or a git clone may carry **several** modules: when its root has a `modules/`
115
- folder, each `modules/<name>/` with a `dreamteamer` key in its `package.json` is a module on that
116
- channel, and the root itself is never compiled. One `npm install` then delivers a whole family, and the
117
- workspace keeps what it wants — a bare module name in `dreamteamer.disable` drops a module before
118
- compile looks at it (an entry with a slash, `<module>/<entity>`, still disables one entity):
119
-
120
- ```json
121
- "dreamteamer": { "disable": ["recordings", "introspection"] }
122
- ```
123
-
124
- Disabling a module another one declares in `dependencies` is refused, naming what is present. The
125
- workspace's own `modules/*` never nest.
126
-
127
- Sources live **flat at a module root** — `modules/crm/skills/`, beside `package.json` — and a folder
128
- at a module root that isn't a known kind is a compile error rather than a silent skip.
129
-
130
- ### Modules are not rigid
131
-
132
- This is the part that differs from npm on purpose.
133
-
134
- Installing a module into a workspace that already has opinions — its own idea of what a `contact` is —
135
- is a **negotiation, not an overwrite**. Four workspaces wanted a CRM and all four wanted a different
136
- `contacts`. A hard import would force one answer and make every divergence a fork.
137
-
138
- Two same-name collections is a compile error that names both descriptors and tells you the move:
139
- declare `extends: <module>/<collection>` and overlay only what differs. Because every schema is one
140
- small YAML file, adapting is cheap — read it, change what doesn't fit, and the diff shows exactly what
141
- you agreed to.
142
-
143
- So domain modules are **recipes you copy and adapt, not packages you install**, and divergence is the
144
- normal case rather than a failure.
145
-
146
- ## Every harness, one source
147
-
148
- `compile` writes `.dreamteamer/` — the single runtime read surface — and from there into per-harness
149
- adapters: Claude Code, Codex, Pi, Gemini CLI, Cursor. Author a skill once; every agent you run sees it.
150
-
151
- ## The editor
152
-
153
- Extension id `dreamteamer.dreamteamer-vscode` (Marketplace · Open VSX). `init` and `compile` write the
154
- `.vscode/extensions.json` recommendation, and `dt status` reports whether it is active.
155
-
156
- [dreamteamer-vscode](https://github.com/dreamteamer/dreamteamer-vscode) gives you tables, boards,
157
- calendars, maps, forms and a data-model designer over the same files — and it loads **the engine your
158
- workspace pins**, so the editor, the CLI and any agent session are provably running the same code.
159
-
160
- ## Docs
161
-
162
- This is an agent-native tool, so its documentation is shipped as skills the agent loads on demand —
163
- and you can read them like any other file:
67
+ ## Extensions
164
68
 
165
- - [`skills/using-dreamteamer`](skills/using-dreamteamer) — the one skill: working with records
166
- (the CLI, conventions, commits) and modeling the workspace (collections, skills, agents,
167
- commands, UI views — and which of those a given request should become), each topic a reference
168
- loaded on demand
169
- - [`docs/one-skill-blast-radius.md`](docs/one-skill-blast-radius.md) — the 0.16.0 skill
170
- consolidation: what breaks for a consumer, what to grep for, which claims were verified live
171
- - [`docs/repos-and-modules.md`](docs/repos-and-modules.md) — attached repos vs modules, and why they
172
- have different homes
173
- - [`docs/namespaces-blast-radius.md`](docs/namespaces-blast-radius.md) — scoping collections under a
174
- namespace (`health/doctors`), what it costs consumers, and why the default namespace is transparent
175
- - [`UPDATING.md`](UPDATING.md) — what to do when upgrading, one section per release
69
+ An extension adds verbs, source kinds or harnesses through one contract
70
+ ([`references/extensions.md`](skills/using-dreamteamer/references/extensions.md)). It can be a
71
+ workspace module (`modules/<id>/package.json` declaring `dreamteamer.extension`) or an installed
72
+ dependency.
176
73
 
177
- ## What it isn't
74
+ Behaviour proofs, worktrees, the REST API, the NotebookLM exporter and the local Docker host left core
75
+ in 0.31.0 and return as extensions. None is published yet.
178
76
 
179
- Not a database — records are files and git is the history. Not a cloud service — there is no server
180
- and no account. Not a note-taking app — it's the layer underneath one.
77
+ ## Agent-Native Documentation
181
78
 
182
- And it is **not** for data that needs row-level access control, field-level encryption, or provable
183
- erasure. Git cannot do those, and pretending otherwise is how people get hurt. This is for
184
- human-scale structured knowledge: thousands of records, not millions.
79
+ Because this is an agent-native tool, documentation is shipped as skills your agent loads on demand:
80
+ - [`skills/using-dreamteamer`](skills/using-dreamteamer) — Core skill for working with records and modeling the workspace.
81
+ - [`docs/`](docs/) — Deeper architectural context, upgrade guides, and rationale.
185
82
 
186
83
  ## Contributing
187
84
 
188
- Issues are welcome. For anything larger than a typo, please open a discussion before a pull request —
189
- this is a small, deliberately lean codebase (`npm run metrics` enforces size budgets), and it's better
190
- to agree on the shape first.
85
+ We welcome issues and discussions! For anything larger than a typo, please open a discussion before submitting a PR. This is a deliberately lean codebase and we prefer to agree on shape first. `npm run verify` enforces our size and test budgets.
191
86
 
192
- `npm run verify` is the gate: import-layer direction, size budgets, and the test suite (tiers 1+2,
193
- zero dependencies, a few seconds). See [CONTRIBUTING.md](CONTRIBUTING.md).
87
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for details.
194
88
 
195
89
  ## License
196
90
 
197
- Apache-2.0 © 2026 Gilad Khen. See [LICENSE](LICENSE).
91
+ [Apache-2.0](LICENSE) © 2026 Gilad Khen.
@@ -67,15 +67,6 @@ schema:
67
67
  have lived in `modules/<module>/<kind>/` since the 2026-08-05 flatten, and a `system/`
68
68
  prefix is only how `runtime.js` recognises a RUNTIME collection in a descriptor compiled
69
69
  by a pre-flatten engine.
70
- driver:
71
- type: string
72
- description: >-
73
- The name of an engine DRIVER that answers this collection's verbs instead of a folder of
74
- files — `docker` is the one shipped (src/containers.js: `containers`, `images`). A driver
75
- collection has no records on disk: its derived `path` names a folder that never exists,
76
- so check, commit and the store read zero records and never write one; the CLI and the REST
77
- route dispatch to the driver first. A string checked against the drivers the engine has,
78
- not an enum — one implementation, and a second is a code change, not a vocabulary change.
79
70
  codec:
80
71
  type: string
81
72
  enum: [md, yaml, json, file]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dreamteamer",
3
- "version": "0.30.0",
3
+ "version": "0.31.0",
4
4
  "description": "A workspace compiler for coding agents — schema-validated records as plain files over git, compiled into every harness",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Gilad Khen <giladkhen@gmail.com>",
@@ -28,6 +28,19 @@
28
28
  "engines": {
29
29
  "node": ">=20"
30
30
  },
31
+ "main": "./src/api.js",
32
+ "types": "./src/api.d.ts",
33
+ "exports": {
34
+ ".": {
35
+ "types": "./src/api.d.ts",
36
+ "default": "./src/api.js"
37
+ },
38
+ "./records": {
39
+ "types": "./src/records-api.d.ts",
40
+ "default": "./src/records-api.js"
41
+ },
42
+ "./package.json": "./package.json"
43
+ },
31
44
  "bin": {
32
45
  "dreamteamer": "bin/dreamteamer.js",
33
46
  "dt": "bin/dreamteamer.js"
@@ -47,7 +60,6 @@
47
60
  "dependencies": {
48
61
  "ajv": "^8.17.1",
49
62
  "ajv-formats": "^3.0.1",
50
- "express": "^5.2.1",
51
63
  "fractional-indexing": "^4.0.0",
52
64
  "js-yaml": "^4.1.0",
53
65
  "yaml": "2.8.4"
@@ -63,7 +63,11 @@ dispatch, so it cannot drift):
63
63
  - read & measure — `list` `get` `values` `history` `diff` `next` `relations` `resolve`
64
64
  - write & publish — `add` `set` `rm` `rename` `move` `revert` `commit`
65
65
  - fields (sources, through the compile gate) — `add-field` `set-field` `rm-field` `rename-field` (system entities — modules, collections, skills, ui-views… — take the RECORD verbs above)
66
- - workspace — `init` `install` `land` `update` `compile` `check` `prove` `status` `start` `changes` `export` `help`
66
+ - workspace — `init` `install` `update` `compile` `check` `status` `changes` `help`
67
+ - an EXTENSION (a workspace module or a dependency declaring `dreamteamer.extension`) adds verbs of
68
+ its own, and `dt help` lists them under its name; each ships the skill that teaches it. A verb that
69
+ answers "left core in 0.31.0" (`dt prove` · `dt land` · `dt worktree` · `dt serve` · `dt notebooklm` · the Docker
70
+ host) has no published extension yet — see `references/extensions.md`.
67
71
 
68
72
  don't learn syntax from prose, this skill included: prose drifts, and `help` ships in
69
73
  the same file as the dispatch it documents. run it once before your first write of a session.
@@ -99,17 +103,15 @@ Load by the map; nothing here is loaded "just in case".
99
103
  | a brand-new or empty workspace, dreamteamer over an existing pile of files, "help me set this up" | `references/getting-started.md` |
100
104
  | read, create, update, rename, delete, commit — or UNDO — a record | `references/records.md` |
101
105
  | "what changed while I was away" | `references/changes.md` |
102
- | the workspace has to reach a reader that is not a coding agent — a NotebookLM notebook; "which fields are sensitive" | `references/exporting.md` |
103
106
  | the workspace seems unable to do something — a new kind of thing, a missing capability, "don't we already have this?" | `references/before-you-build.md` (look first); a new model then continues `references/data-modeling.md` (decide) → `references/collections.md` (write it) |
104
107
  | a collection or field, mechanically — the descriptor, the system and field verbs, `templates:`/`extends:`, a compile or check message | `references/collections.md` |
105
108
  | knowledge a session should find on its own | `references/skills.md` |
106
109
  | "let me type one word and have this done" | `references/commands.md` |
107
110
  | "which command applies to this record?" — a binding, a gate | `references/commands.md` |
108
- | "how would anyone know this still works?" — a proof of a skill, a command or a script, and the exit code `dt prove` answers with | `references/proofs.md` |
109
111
  | a job needing a fresh context and its own tools | `references/agents.md` |
110
112
  | a route, a nav entry, a board / calendar / map over records | `references/ui-views.md` |
111
113
  | a rendering or editing behaviour nothing registered has | `references/ui-components.md` |
112
- | a second checkout — making one ready, landing its records, a harness that cuts them for you | `references/worktrees.md` |
114
+ | an optional tool — behaviour proofs, worktrees, a REST server, an exporter, a new harness — and whether to write one | `references/extensions.md` |
113
115
  | other agent sessions are running on this machine — finding them, messaging one, coordinating several, and what may not cross between them | `references/sessions.md` |
114
116
 
115
117
  three act-two tie-breakers, because they are the ones that go wrong:
@@ -131,7 +133,8 @@ workspace's decision log (where one exists) wins over older documents.
131
133
  ## system entities take the RECORD verbs
132
134
 
133
135
  Modules, collections, skills, agents, commands, command-bindings, ui-views, collection-templates
134
- and proofs are collections in the runtime, and since 0.19.0 the ordinary verbs write them:
136
+ — and any kind an installed extension contributes — are collections in the runtime, and since
137
+ 0.19.0 the ordinary verbs write them:
135
138
 
136
139
  ```
137
140
  dt add modules --name core --description "The shared nouns."
@@ -143,9 +146,8 @@ dt set modules/hr namespaces=hr dependencies=modules/core
143
146
  dt rm modules/hr --force # --dry-run first; it prints its plan
144
147
  ```
145
148
 
146
- ⚠ **`proofs` is the one exception, and only to `add`:** a proof is hand-authored like a skill or a
147
- command, so `dt add proofs` is refused, naming the file to write
148
- (`modules/<module>/proofs/<id>.proof.yaml`, `references/proofs.md`). Every other verb works on it.
149
+ ⚠ **`add` scaffolds skills only.** Agents, commands, bindings, templates and contributed kinds are
150
+ hand-authored — `dt add agents` is refused, naming the file to write. Every other verb works on them.
149
151
 
150
152
  `dt schema <op>` is **gone** since 0.19.0 and fails with the translation printed. `UPDATING.md` has
151
153
  the complete mapping table.
@@ -49,9 +49,10 @@ Only after all four: build it, in the module that owns the concept.
49
49
 
50
50
  ## name the proof before you build it
51
51
 
52
- **Before writing the thing, say how anyone would know it works** — one sentence, in the shape a
53
- `proofs` record takes: *this record, in this state, after this step, must look like this*
54
- (`proofs.md`). It costs a minute and it is the cheapest design review there is.
52
+ **Before writing the thing, say how anyone would know it works** — one sentence: *this record, in
53
+ this state, after this step, must look like this*. It costs a minute and it is the cheapest design
54
+ review there is. (With a proofs extension installed, that sentence is exactly the shape of a
55
+ `proofs` record, and `dt prove` runs it — its own skill says how.)
55
56
 
56
57
  ⚠ **When you cannot name one, the artifact has no observable post-state, and THAT is the first
57
58
  thing to change** — not something to note and carry on past. A skill nothing can check is a skill
@@ -151,11 +151,11 @@ they read stay honest:
151
151
  `{ summary: { _nempty: true } }` works the moment `summary` is a mirror — or ship the binding
152
152
  without a `can-exit` and accept that it never shows done. What is not honest is a proxy field a
153
153
  human must remember to set.
154
- - **A `can-exit` and a proof's `count` answer different questions — put each expectation on its own
155
- side.** A gate is a filter over ONE record, evaluated on every render of `dt next` and every board
154
+ - **A `can-exit` and a proof's `count` (a proofs extension) answer different questions — put
155
+ each expectation on its own side.** A gate is a filter over ONE record, evaluated on every render of `dt next` and every board
156
156
  the studio draws, so it can only ever read that record's own fields (plus one outbound hop) — which
157
157
  is exactly the gap the bullet above names: "a summary referencing this record exists" is
158
- inexpressible there. A **proof** (`proofs.md`) is evaluated on demand and is collection-scoped, so
158
+ inexpressible there. A **proof** is evaluated on demand and is collection-scoped, so
159
159
  it says the thing a gate cannot: `{ collection: summaries, where: { about: { _eq: '{record}' } },
160
160
  count: { _delta: 1 } }` — *running this command left one more summary behind*. (`{record}` inside a
161
161
  proof's `where` is SUBSTITUTED with the picked record's reference before the filter runs, which is
@@ -0,0 +1,60 @@
1
+ # extensions — optional tools, and the one seam they plug into
2
+
3
+ Core is records plus the workspace compiler. Anything with a lifecycle of its own — a server, a
4
+ Docker host, a behaviour-test runner, an exporter to one vendor — is an **extension**: code the engine
5
+ calls, which a workspace has when it wants that capability and does without otherwise.
6
+
7
+ The verbs that left core in 0.31.0 — `prove` · `land` · `worktree`, `serve`, `notebooklm`, and the
8
+ Docker host — return as extensions, and **none is published yet**. Typed against core, each fails with
9
+ exit 2 and says so. A workspace that needs one now carries it as its own module (below), or stays on
10
+ 0.30.x.
11
+
12
+ `dt status` lists the extensions this workspace loaded, and `dt help` appends each one's usage.
13
+
14
+ ## how a workspace turns one on
15
+
16
+ Two places, one declaration — a `package.json` carrying `"dreamteamer": { "extension": "./entry.js" }`:
17
+
18
+ - **a workspace module**, `modules/<id>/package.json`. Its code is the workspace's own, like `bin/`,
19
+ so it needs no package and no npm. This is how a workspace carries an extension nobody has
20
+ published, and it shadows a dependency of the same name.
21
+ - **a direct dependency.** npm put the code there on purpose; a transitive package is never loaded
22
+ however it advertises.
23
+
24
+ A bare entry in `dreamteamer.disable` switches one off while leaving it in place. Two extensions
25
+ claiming the same verb, source kind or harness is a refusal at load, naming both — never "last one
26
+ wins".
27
+
28
+ An extension is ALSO a content module (its `dreamteamer` key makes it one): its collections and skills
29
+ travel with its code, and compile discovers them like any other module's.
30
+
31
+ ⚠ **Remove an extension and its kind goes with it.** A workspace holding `proofs/` folders with no
32
+ extension contributing `proofs` fails compile on the unknown folder — deliberately: a proof that
33
+ compiles with no validator would be a claim nothing checks. The next compile after a removal also
34
+ prunes the extension's compiled folder and its managed blocks.
35
+
36
+ ## writing one — the contract
37
+
38
+ The entry's default export is `activate(dt)`. `dt` is the RUNNING engine's public API
39
+ (`import('dreamteamer')`'s namespace), so the extension never imports an engine of its own and can
40
+ never disagree with the one the operator ran. It returns a contribution; every key is optional:
41
+
42
+ | key | shape | what core does with it |
43
+ |---|---|---|
44
+ | `commands` | `{ <verb>: { usage, run(ws, argv) } }` | `dt <verb> …` runs it in-process with the opened workspace; the return is the exit code |
45
+ | `sourceKinds` | `[{ kind, exclude?: [subtree] }]` | compile stages `<module>/<kind>/` like a built-in kind; `exclude` keeps fixtures out |
46
+ | `analyze` | `(draft) → { errors?, warnings?, notes? }` | runs after assembly, before any output is replaced; an error fails the compile (and every schema write, which compiles) |
47
+ | `harnesses` | `{ <id>: (ctx) → { blocks: { <file>: text }, summary } }` | a harness adapter writing managed blocks into user-owned files |
48
+ | `orientation` | a string | one paragraph appended to every orientation block |
49
+ | `hooks` | `{ <ClaudeHookEvent>: '<dt verb args>' }` | merged into `dt install --print-adapters` |
50
+
51
+ The `draft` is data only: the staged entries, the final merged descriptors, the modules, declared var
52
+ and env key NAMES, and the previous manifest. No writer, no Store, no environment values — an analysis
53
+ that needs one is a command, not an analysis.
54
+
55
+ ## a module, or an extension?
56
+
57
+ A **module** ships collections, skills, commands, agents, views and UI code — content. An
58
+ **extension** ships code the engine calls. Reach for an extension only when the capability needs one
59
+ of the contribution keys above; everything else is a module, and a module is copied and adapted per
60
+ workspace rather than installed (`references/before-you-build.md`).
@@ -6,7 +6,7 @@ refusals that keep that from looping, lying, or carrying private data somewhere
6
6
 
7
7
  The whole design turns on one asymmetry. Two sessions in the same tree are conflict-BLIND, and so are
8
8
  two sessions in one conversation: **the second write wins and nobody is told.** Sessions are
9
- `worktrees`' twin — observed, never stored, and the registry is the authority rather than anyone's
9
+ git worktrees' twin — observed, never stored, and the registry is the authority rather than anyone's
10
10
  memory of it.
11
11
 
12
12
  | the question | read |
@@ -175,10 +175,9 @@ A coordinator spans repos by construction, and one of them may publish.
175
175
  records it may not message a publishing session at all, whatever it means to say. This is what
176
176
  keeps rule 1 safe after compaction, when it can no longer recall precisely what it read.
177
177
  6. ⚠ **`cwd` is not the repo, and one repo is not one tree.** Harnesses put worktrees *inside* the
178
- repo or *under the home directory* depending on the harness (`references/worktrees.md`). A `cwd`
179
- under a harness's own worktree root is still that repo and carries its full boundary — so a
180
- path-prefix test against the primary root gets it wrong in the dangerous direction. `dt list
181
- worktrees` is the instrument.
178
+ repo or *under the home directory* depending on the harness. A `cwd` under a harness's own
179
+ worktree root is still that repo and carries its full boundary — so a path-prefix test against
180
+ the primary root gets it wrong in the dangerous direction. `git worktree list` is the instrument.
182
181
 
183
182
  ## not stepping on your own toes
184
183
 
@@ -160,12 +160,10 @@ Skills ship with modules and are read by any operator on any machine:
160
160
  renamed verb or a changed limit in a skill sends every future session down the old path
161
161
  confidently. When you catch a skill lying, fixing it is part of the task you are on, not a
162
162
  follow-up.
163
- - **Give it a proof, and know what a proof cannot cover.** A `proofs` record (`proofs.md`) pins the
163
+ - **Give it a mechanical check, and know what one cannot cover.** Something must pin the
164
164
  mechanical half: the script the skill names runs, the record it promises appears, the path it
165
- files to exists. Write it in the same commit — `dt add skills` nudges you with the path the moment
166
- it writes the skill (compile's own nudge covers new commands and scripts, never skills), and
167
- `dt list proofs --missing` names every artifact nobody claimed anything about. ⚠ **A
168
- green proof is not evidence the skill TEACHES.** Whether a fresh session finds it, loads it and
165
+ files to exists — in a workspace with a proofs extension, that is a `proofs` record, written
166
+ in the same commit. ⚠ **A green check is not evidence the skill TEACHES.** Whether a fresh session finds it, loads it and
169
167
  does the job right is the eval layer: real tasks, blind sessions, a scoring sheet — a procedure,
170
168
  never something the engine runs.
171
169
  - **Retire what nothing loads.** A skill nobody uses still costs its line in every session's index.
package/src/api.d.ts ADDED
@@ -0,0 +1,109 @@
1
+ // The typed contract of `import … from 'dreamteamer'` (src/api.js). It re-exports the record half
2
+ // (`dreamteamer/records`, src/records-api.d.ts) and adds the workspace half. A test pins each runtime
3
+ // export list to its declaration, so a name added to one and not the other fails the suite.
4
+
5
+ export * from './records-api.js';
6
+ import type { Fields, Descriptor, Descriptors, Manifest, Store } from './records-api.js';
7
+
8
+ // ---- the workspace and extensions ------------------------------------------------------------------
9
+
10
+ export interface Workspace {
11
+ /** absolute path of the workspace root */
12
+ root: string;
13
+ /** the workspace package.json */
14
+ pkg: { name?: string; dependencies?: Record<string, string>; devDependencies?: Record<string, string>; dreamteamer?: Record<string, any>; [k: string]: unknown };
15
+ /** the ACTIVATED extensions, present on a handle from `openWorkspace` */
16
+ extensions?: LoadedExtension[];
17
+ }
18
+
19
+ /** What an extension's `activate(dt)` returns. Every key is optional. */
20
+ export interface Contribution {
21
+ commands?: Record<string, { usage?: string; run(ws: Workspace, argv: string[]): number | void | Promise<number | void> }>;
22
+ sourceKinds?: (string | { kind: string; exclude?: string[] })[];
23
+ analyze?(draft: CompileDraft): { errors?: string[]; warnings?: string[]; notes?: string[] } | void;
24
+ harnesses?: Record<string, (ctx: HarnessContext) => { blocks?: Record<string, string | null>; summary?: string } | void>;
25
+ orientation?: string | ((ctx: { entries: Map<string, Entry> }) => string);
26
+ hooks?: Record<string, string>;
27
+ }
28
+ export type Activate = (dt: typeof import('./api.js')) => Contribution | Promise<Contribution>;
29
+ export interface LoadedExtension {
30
+ name: string;
31
+ version: string;
32
+ commands: NonNullable<Contribution['commands']>;
33
+ sourceKinds: { kind: string; exclude: string[]; extension: string }[];
34
+ analyze: Contribution['analyze'] | null;
35
+ harnesses: NonNullable<Contribution['harnesses']>;
36
+ orientation: Contribution['orientation'] | null;
37
+ hooks: Record<string, string>;
38
+ }
39
+ export type Entry = { sources: { path: string; hash: string }[]; bytes: Buffer };
40
+ export interface CompileDraft {
41
+ /** runtime-relative path → staged entry; read-only */
42
+ readonly entries: Map<string, Entry>;
43
+ /** the FINAL merged descriptors */
44
+ readonly descriptors: Descriptors;
45
+ readonly modules: { id: string; name: string; root: string; channel: 'inline' | 'git' | 'npm' }[];
46
+ /** names only — never values */
47
+ readonly declaredVars: string[];
48
+ readonly declaredEnv: string[];
49
+ readonly previousManifest: Manifest | null;
50
+ /** parse one staged YAML entry, with its source path in any error */
51
+ parse(runtimePath: string): any;
52
+ }
53
+ export interface HarnessContext {
54
+ entries: Map<string, Entry>;
55
+ version: string;
56
+ collections: { name: string; generated: boolean; systemGroup: boolean; description: string; module: string; sensitive: boolean; sensitiveFields: string[] }[];
57
+ modules: { id: string; title: string; description: string; path: string }[];
58
+ }
59
+
60
+ export const EXTENSION_API: 1;
61
+ export function openWorkspace(start?: string): Promise<Workspace & { extensions: LoadedExtension[] }>;
62
+ export function findWorkspace(start?: string): Workspace;
63
+ export function declaredExtensions(ws: Workspace): { name: string; version: string; dir: string; entry: string }[];
64
+ export const engineBin: string;
65
+ export const engineRoot: string;
66
+
67
+ export function envContext(ws: Workspace): unknown;
68
+ export function renderTemplate(template: string, ctx: unknown): string;
69
+ export function parseEnvValues(text: string): Map<string, string>;
70
+ export function satisfies(version: string, range: string): boolean | null;
71
+
72
+ // ---- the compiler, schema and module operations --------------------------------------------------
73
+
74
+ /** throws CompileError on a bad source; prints its summary; returns 0 */
75
+ export function compile(ws: Workspace): 0;
76
+ export function staleness(root: string): { compiled: boolean; stale: string[]; manifest?: Manifest; message?: string };
77
+ export function warnIfStale(root: string): ReturnType<typeof staleness>;
78
+ export function discoverModules(root: string, pkg: Workspace['pkg']): { modules: { name: string; root: string; channel: string }[]; shadows: unknown[]; disabledModules: string[] };
79
+ export class CompileError extends Error {}
80
+ export const KINDS: readonly string[];
81
+ export const MANAGED_BLOCKS: readonly { id: 'orientation' | 'instructions'; begin: string; end: string }[];
82
+ type SchemaOp = (ws: Workspace, store: Store, ...args: any[]) => any;
83
+ export const createCollection: SchemaOp, removeCollection: SchemaOp, renameCollection: SchemaOp, moveCollection: SchemaOp, setCollectionScalars: SchemaOp;
84
+ export const addField: SchemaOp, updateField: SchemaOp, removeField: SchemaOp, removeFieldPlan: SchemaOp, renameField: SchemaOp, renameFieldPlan: SchemaOp;
85
+ export function fieldDef(store: Store, flags: Record<string, unknown>, collection: string): any;
86
+ export function statedKeywords(flags: Record<string, unknown>): any;
87
+ export const saveUiView: SchemaOp, removeUiView: SchemaOp;
88
+ export const createModule: SchemaOp, setModule: SchemaOp, renameModule: SchemaOp, removeModule: SchemaOp;
89
+ export const createSkill: SchemaOp, refuseHandAuthored: SchemaOp, removeEntity: SchemaOp, renameEntity: SchemaOp, setEntityFrontmatter: SchemaOp;
90
+ export function init(opts?: { flags?: Record<string, string> }): 0;
91
+ export function ensureRepo(ws: Workspace, id: string): { path: string; cloned: boolean };
92
+ export function ensureAllRepos(ws: Workspace): { path: string; cloned: boolean }[];
93
+ export function listRepos(ws: Workspace): { id: string; path: string; present: boolean; unresolved?: string }[];
94
+ export function installClone(ws: Workspace, url: string, name?: string): number;
95
+
96
+ // ---- the checkout -------------------------------------------------------------------------------------
97
+
98
+ export function describeCheckout(root: string, git?: (args: string[], cwd: string) => string): { root: string; kind: 'primary' | 'linked'; gitDir: string; commonDir: string; primary: string; insideRoot: boolean };
99
+ export function installCommand(ws: Workspace, argv: string[], opts?: { open?: (at: string) => Promise<Workspace> }): Promise<number>;
100
+ export function resolveNpm(execPath?: string, env?: NodeJS.ProcessEnv): string | null;
101
+ export function childEnv(): NodeJS.ProcessEnv;
102
+ export function readHookInput(stdinText: string): { cwd: string | null; name: string | null; raw: Record<string, unknown> };
103
+ export function readStdin(isTTY?: boolean): string;
104
+
105
+ // ---- CLI helpers ------------------------------------------------------------------------------------------
106
+
107
+ /** write `text` plus a trailing newline, synchronously, looping on short writes — safe before process.exit */
108
+ export function emit(text: string, fd?: number): void;
109
+ export function parseArgs(argv: string[]): { flags: Record<string, string | boolean | string[]>; pos: string[] };