dreamteamer 0.30.0 → 0.32.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 +47 -153
- package/collections/collections.collection.yaml +26 -9
- package/package.json +14 -2
- package/skills/using-dreamteamer/SKILL.md +16 -10
- package/skills/using-dreamteamer/references/before-you-build.md +4 -3
- package/skills/using-dreamteamer/references/collections.md +71 -1
- package/skills/using-dreamteamer/references/commands.md +3 -3
- package/skills/using-dreamteamer/references/data-modeling.md +9 -1
- package/skills/using-dreamteamer/references/extensions.md +60 -0
- package/skills/using-dreamteamer/references/records.md +17 -0
- package/skills/using-dreamteamer/references/sessions.md +4 -5
- package/skills/using-dreamteamer/references/skills.md +3 -5
- package/src/api.d.ts +109 -0
- package/src/api.js +70 -0
- package/src/check.js +57 -2
- package/src/checkout.js +105 -330
- package/src/cli.js +90 -274
- package/src/collections-cli.js +16 -165
- package/src/commit.js +7 -0
- package/src/compile.js +211 -155
- package/src/events.js +7 -2
- package/src/extensions.js +135 -0
- package/src/filter.js +1 -1
- package/src/harnesses.js +82 -135
- package/src/init.js +9 -3
- package/src/placement.js +209 -0
- package/src/records-api.d.ts +103 -0
- package/src/records-api.js +40 -0
- package/src/runtime.js +2 -2
- package/src/schema-ops.js +26 -9
- package/src/store.js +396 -35
- package/collections/containers.collection.yaml +0 -81
- package/collections/images.collection.yaml +0 -46
- package/collections/proofs.collection.yaml +0 -96
- package/skills/using-dreamteamer/references/exporting.md +0 -53
- package/skills/using-dreamteamer/references/proofs.md +0 -435
- package/skills/using-dreamteamer/references/worktrees.md +0 -235
- package/src/container-archive.js +0 -356
- package/src/containers.js +0 -635
- package/src/export-notebooklm.js +0 -502
- package/src/land.js +0 -743
- package/src/prove.js +0 -1922
- package/src/server.js +0 -481
package/README.md
CHANGED
|
@@ -1,14 +1,24 @@
|
|
|
1
1
|
# dreamteamer
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**dreamteamer is a modular AI workspace builder.**
|
|
4
4
|
|
|
5
|
-
|
|
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
|
-
|
|
11
|
-
|
|
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
|
-
|
|
31
|
+
## How It Works
|
|
22
32
|
|
|
23
|
-
|
|
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
|
-
|
|
42
|
-
|
|
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
|
-
|
|
80
|
-
|
|
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
|
-
##
|
|
52
|
+
## Programmatic Usage
|
|
91
53
|
|
|
92
|
-
|
|
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
|
-
|
|
56
|
+
```javascript
|
|
57
|
+
import { openWorkspace, Store } from 'dreamteamer';
|
|
96
58
|
|
|
97
|
-
|
|
98
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
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
|
-
|
|
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
|
-
|
|
180
|
-
and no account. Not a note-taking app — it's the layer underneath one.
|
|
77
|
+
## Agent-Native Documentation
|
|
181
78
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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]
|
|
@@ -100,6 +91,32 @@ schema:
|
|
|
100
91
|
entry:
|
|
101
92
|
type: string
|
|
102
93
|
description: Folder shapes only — the file inside the folder that IS the record (e.g. SKILL.md).
|
|
94
|
+
under:
|
|
95
|
+
type: object
|
|
96
|
+
description: >-
|
|
97
|
+
RELATIONSHIP-BASED STORAGE — records live INSIDE the folder of the record they belong
|
|
98
|
+
to. `{ field: company, path: meetings }` puts a meeting whose `company` is
|
|
99
|
+
`companies/northwind` at `<companies root>/northwind/meetings/<id>.meeting.md`; one with
|
|
100
|
+
no `company` stays in this collection's own `path`, which remains its fallback root.
|
|
101
|
+
Still ONE logical collection: `list` is the union across every parent folder, a
|
|
102
|
+
reference is `<collection>/<id>` wherever the file sits, and the id never changes when
|
|
103
|
+
the owner does — `set <field>=…` MOVES the file. `field` must be a scalar `x-reference`
|
|
104
|
+
to exactly one collection, that collection must be `shape: folder`, and one level is
|
|
105
|
+
supported (a placed collection cannot be a parent). The field is the intended owner and
|
|
106
|
+
the folder is observed placement: `check` reports a disagreement, `dreamteamer relocate`
|
|
107
|
+
reconciles it, nothing infers an owner from where a file was found. Not for a record
|
|
108
|
+
many parents share equally — that is a plain reference.
|
|
109
|
+
required: [field, path]
|
|
110
|
+
properties:
|
|
111
|
+
field:
|
|
112
|
+
type: string
|
|
113
|
+
description: The scalar reference field on THIS collection that names the parent record.
|
|
114
|
+
path:
|
|
115
|
+
type: string
|
|
116
|
+
description: The folder INSIDE each parent record's folder that holds these records — relative, e.g. `meetings`.
|
|
117
|
+
collection:
|
|
118
|
+
type: string
|
|
119
|
+
description: DERIVED by compile, never authored — the parent collection, read off `field`'s x-reference so the record layer never opens a schema to find it.
|
|
103
120
|
repo:
|
|
104
121
|
type: string
|
|
105
122
|
description: DERIVED by compile, never authored — the workspace-relative root of the git repo holding these records ('.' is the workspace). Set from the owning module's `owns-data`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dreamteamer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.32.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"
|
|
@@ -30,7 +30,10 @@ unsure which skill owns the job in front of you.
|
|
|
30
30
|
|
|
31
31
|
- a record is a `<id>.<suffix>.<ext>` file (or a folder, for folder-shape collections). **the id
|
|
32
32
|
is the path** inside the collection folder minus suffix and extension — nested folders join in:
|
|
33
|
-
`data/meetings/2026/07/standup.meeting.md` ⇒ id `2026/07/standup`.
|
|
33
|
+
`data/meetings/2026/07/standup.meeting.md` ⇒ id `2026/07/standup`. a collection may instead keep
|
|
34
|
+
its records INSIDE the folder of the record they belong to (`storage.under` — a company's
|
|
35
|
+
meetings in `data/companies/<company>/meetings/`): still ONE collection, the same id, the same
|
|
36
|
+
`meetings/<id>` reference; only the folder follows the owner field (`references/collections.md`).
|
|
34
37
|
- **references are `<collection>/<id>`** strings — always qualified, greppable, never a bare name
|
|
35
38
|
and never a file path.
|
|
36
39
|
|
|
@@ -61,9 +64,13 @@ dispatch, so it cannot drift):
|
|
|
61
64
|
|
|
62
65
|
- a collection may be spelled in the SINGULAR on any of these (`dt add task "call the bank"` — one bare positional is the title); references inside records still spell the full name
|
|
63
66
|
- read & measure — `list` `get` `values` `history` `diff` `next` `relations` `resolve`
|
|
64
|
-
- write & publish — `add` `set` `rm` `rename` `move` `revert` `commit`
|
|
67
|
+
- write & publish — `add` `set` `rm` `rename` `move` `revert` `commit` `relocate`
|
|
65
68
|
- 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` `
|
|
69
|
+
- workspace — `init` `install` `update` `compile` `check` `status` `changes` `help`
|
|
70
|
+
- an EXTENSION (a workspace module or a dependency declaring `dreamteamer.extension`) adds verbs of
|
|
71
|
+
its own, and `dt help` lists them under its name; each ships the skill that teaches it. A verb that
|
|
72
|
+
answers "left core in 0.31.0" (`dt prove` · `dt land` · `dt worktree` · `dt serve` · `dt notebooklm` · the Docker
|
|
73
|
+
host) has no published extension yet — see `references/extensions.md`.
|
|
67
74
|
|
|
68
75
|
don't learn syntax from prose, this skill included: prose drifts, and `help` ships in
|
|
69
76
|
the same file as the dispatch it documents. run it once before your first write of a session.
|
|
@@ -99,17 +106,16 @@ Load by the map; nothing here is loaded "just in case".
|
|
|
99
106
|
| a brand-new or empty workspace, dreamteamer over an existing pile of files, "help me set this up" | `references/getting-started.md` |
|
|
100
107
|
| read, create, update, rename, delete, commit — or UNDO — a record | `references/records.md` |
|
|
101
108
|
| "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
109
|
| 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
110
|
| a collection or field, mechanically — the descriptor, the system and field verbs, `templates:`/`extends:`, a compile or check message | `references/collections.md` |
|
|
111
|
+
| "keep a company's meetings in the company's folder" — records stored beside the record they belong to, a `placed … but` check report, `dt relocate` | `references/collections.md` (declaring it) · `references/records.md` (working with it) |
|
|
105
112
|
| knowledge a session should find on its own | `references/skills.md` |
|
|
106
113
|
| "let me type one word and have this done" | `references/commands.md` |
|
|
107
114
|
| "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
115
|
| a job needing a fresh context and its own tools | `references/agents.md` |
|
|
110
116
|
| a route, a nav entry, a board / calendar / map over records | `references/ui-views.md` |
|
|
111
117
|
| a rendering or editing behaviour nothing registered has | `references/ui-components.md` |
|
|
112
|
-
|
|
|
118
|
+
| an optional tool — behaviour proofs, worktrees, a REST server, an exporter, a new harness — and whether to write one | `references/extensions.md` |
|
|
113
119
|
| 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
120
|
|
|
115
121
|
three act-two tie-breakers, because they are the ones that go wrong:
|
|
@@ -131,7 +137,8 @@ workspace's decision log (where one exists) wins over older documents.
|
|
|
131
137
|
## system entities take the RECORD verbs
|
|
132
138
|
|
|
133
139
|
Modules, collections, skills, agents, commands, command-bindings, ui-views, collection-templates
|
|
134
|
-
and
|
|
140
|
+
— and any kind an installed extension contributes — are collections in the runtime, and since
|
|
141
|
+
0.19.0 the ordinary verbs write them:
|
|
135
142
|
|
|
136
143
|
```
|
|
137
144
|
dt add modules --name core --description "The shared nouns."
|
|
@@ -143,9 +150,8 @@ dt set modules/hr namespaces=hr dependencies=modules/core
|
|
|
143
150
|
dt rm modules/hr --force # --dry-run first; it prints its plan
|
|
144
151
|
```
|
|
145
152
|
|
|
146
|
-
⚠ **`
|
|
147
|
-
|
|
148
|
-
(`modules/<module>/proofs/<id>.proof.yaml`, `references/proofs.md`). Every other verb works on it.
|
|
153
|
+
⚠ **`add` scaffolds skills only.** Agents, commands, bindings, templates and contributed kinds are
|
|
154
|
+
hand-authored — `dt add agents` is refused, naming the file to write. Every other verb works on them.
|
|
149
155
|
|
|
150
156
|
`dt schema <op>` is **gone** since 0.19.0 and fails with the translation printed. `UPDATING.md` has
|
|
151
157
|
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
|
|
53
|
-
|
|
54
|
-
|
|
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
|
|
@@ -172,7 +172,77 @@ is copied.
|
|
|
172
172
|
- Nested namespaces work (`work/clients`); the longest declared prefix wins.
|
|
173
173
|
- ⚠ **No collection may store records inside another's folder** — a namespace folder cannot
|
|
174
174
|
itself be a collection root. Compile refuses it, because the outer collection would index the
|
|
175
|
-
inner one's records as its own.
|
|
175
|
+
inner one's records as its own. The one DECLARED exception is the next section: a collection
|
|
176
|
+
stored under the records of a folder-shape parent, where compile knows exactly which files
|
|
177
|
+
belong to whom.
|
|
178
|
+
|
|
179
|
+
## relationship-based storage — records beside the record they belong to
|
|
180
|
+
|
|
181
|
+
A collection can keep each record INSIDE the folder of the record it belongs to, so a company's
|
|
182
|
+
folder holds the company's meetings and a browse of `data/companies/northwind/` shows the whole
|
|
183
|
+
account. It is declared on the CHILD's `storage`, in one line, and changes nothing about what the
|
|
184
|
+
collection IS:
|
|
185
|
+
|
|
186
|
+
```yaml
|
|
187
|
+
# modules/default/collections/meetings.collection.yaml
|
|
188
|
+
storage: { path: data/meetings, suffix: meeting, under: { field: company, path: meetings } }
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
```text
|
|
192
|
+
data/companies/northwind/company.md ← the parent: shape: folder, entry: company.md
|
|
193
|
+
data/companies/northwind/meetings/2026/10/kickoff.meeting.md ← meetings/2026/10/kickoff, company: companies/northwind
|
|
194
|
+
data/meetings/2026/10/offsite.meeting.md ← meetings/2026/10/offsite, no company: the FALLBACK root
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
- **Still one logical collection.** `dt list meetings` is the union across every company folder
|
|
198
|
+
and the fallback root, ordered by id; `dt get meetings/2026/10/kickoff` finds the file wherever it
|
|
199
|
+
sits; a reference is `meetings/<id>` everywhere. Nothing is spelled per company — no descriptor,
|
|
200
|
+
no skill, no view.
|
|
201
|
+
- **The id is independent of placement.** `dt set meetings/<id> company=companies/harbor` MOVES
|
|
202
|
+
the file into Harbor's folder and changes nothing else: not the id, not one inbound reference.
|
|
203
|
+
Clearing the field moves it back to the fallback root. An id is unique across every root, and a
|
|
204
|
+
second file claiming one is a `check` violation and a write refusal, never last-one-wins.
|
|
205
|
+
- **`field`** is a scalar `x-reference` to exactly ONE collection (a list has no single folder; a
|
|
206
|
+
union has no single parent). **`path`** is a relative folder inside each parent record's folder.
|
|
207
|
+
compile derives `under.collection` from the field; nothing else is authored.
|
|
208
|
+
- **The parent must be `shape: folder`** (`storage: { shape: folder, entry: company.md }`) — only
|
|
209
|
+
a folder can hold anything beside the record. A file-shape collection that should become a
|
|
210
|
+
parent changes its descriptor to folder shape, and `dt relocate <collection>` then moves each
|
|
211
|
+
`<id>.<suffix>.md` into `<id>/<entry>` with its id unchanged (`check` names them until it runs).
|
|
212
|
+
- **One level.** A placed collection cannot itself be a parent; the child is a text record
|
|
213
|
+
(`md` · `yaml` · `json`, file shape) — an opaque or folder-shape child is refused for now. Two
|
|
214
|
+
children of one parent need two different paths, and a path never equals the parent's entry.
|
|
215
|
+
- **The field is the owner; the folder is observed placement.** A file found under the wrong
|
|
216
|
+
company — moved by hand, or sitting in the fallback root from before the declaration existed — is
|
|
217
|
+
`placed under … but <field> is …` in `check`, which changes nothing. `dt relocate <collection>`
|
|
218
|
+
(or `<collection>/<id>`, `--dry-run` first) moves files to where the compiled descriptor puts
|
|
219
|
+
them and refuses a source with unpublished changes or an occupied destination. Editing some OTHER
|
|
220
|
+
field never relocates as a side effect; nothing ever infers an owner from where a file was found.
|
|
221
|
+
- **A parent with records inside its folder cannot be removed** — not with `--force` either;
|
|
222
|
+
reassign or clear their owner first. Renaming the parent carries the folder with everything in
|
|
223
|
+
it and rewrites the children's owner field; their ids do not change.
|
|
224
|
+
- **Adopting it on existing data is three explicit steps**, each reviewable: make the parent folder
|
|
225
|
+
shape and `relocate` it; add `under` to the child and compile (no file moves at compile — `check`
|
|
226
|
+
reports every mismatch); `relocate` the child, `--dry-run` first. `dt commit` stages a moved
|
|
227
|
+
record's old and new path together; `dt revert` of an owner change moves the file back.
|
|
228
|
+
- **Removing or changing `under` is the same walk backwards, and compile holds the door.** While
|
|
229
|
+
records still sit inside parent folders, a compile that drops the declaration, changes its
|
|
230
|
+
`path`, or moves the PARENT collection's `storage.path` is REFUSED — the new descriptor would stop
|
|
231
|
+
every reader seeing them. The order is
|
|
232
|
+
`dt relocate <collection> --to-root` (every placed record back into the collection's own folder,
|
|
233
|
+
ids unchanged, under the still-current declaration) → edit the descriptor → compile → `dt relocate
|
|
234
|
+
<collection>` to place them under the new path. The same order renames a placed collection.
|
|
235
|
+
- **`relocate` refuses before it moves anything**: a dangling or malformed owner field (fix the
|
|
236
|
+
field first — it never makes a folder for a parent that does not exist), an occupied destination,
|
|
237
|
+
a source with unpublished changes, or a destination behind a symlink. One problem refuses the
|
|
238
|
+
whole plan; `--dry-run` reports it.
|
|
239
|
+
- **Inside a parent's folder, only real entries count.** A symlink at a child root, on the way to
|
|
240
|
+
one, or anywhere beneath one — a folder or a file — is never written through and never read as a
|
|
241
|
+
record; `check` names it. The collection's own roots (`data/`, `storage.path`) are not subject to
|
|
242
|
+
this; the rule is about what a record folder may contain.
|
|
243
|
+
- **When NOT to use it.** A record several parents share equally, a record whose owner is usually
|
|
244
|
+
unknown, or a collection nobody browses as a folder — keep conventional storage and a plain
|
|
245
|
+
reference. Folder grouping is a browsing convenience, never a permission boundary.
|
|
176
246
|
|
|
177
247
|
## `templates:` — a live shared field set
|
|
178
248
|
|
|
@@ -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
|
|
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**
|
|
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
|
|
@@ -300,7 +300,15 @@ roadmap, not a model; wait for the second consumer.
|
|
|
300
300
|
`max_bytes` (default 200 KB). A big binary is not a record: it lives outside the vault under a
|
|
301
301
|
declared var, with an ordinary record carrying the `${env:...}` template that points at it.
|
|
302
302
|
- **`shape: folder` when a record is intrinsically several files** (a skill with references beside
|
|
303
|
-
it)
|
|
303
|
+
it), or when OTHER collections' records should live inside it — see the next bullet. Otherwise
|
|
304
|
+
prefer one file until the record itself demands companions.
|
|
305
|
+
- **`storage.under` when people browse a parent as a unit** — a company folder holding that
|
|
306
|
+
company's meetings, a case folder holding its documents. It is one line on the CHILD
|
|
307
|
+
(`under: { field: company, path: meetings }`), the collection stays ONE collection with the same
|
|
308
|
+
ids and references, and the owner field is what moves a file (`collections.md`). Choose ONE
|
|
309
|
+
physical owner and leave every other relationship a plain reference; keep conventional storage
|
|
310
|
+
when no single owner is sensible, when the owner is usually unknown, or when nobody would open
|
|
311
|
+
the folder. It organises files; it grants nothing.
|
|
304
312
|
- **Machine-specific paths are templates, never absolute paths.** `${env:FILES_FOLDER}/…` is inert
|
|
305
313
|
data rendered per machine by `dt resolve`; an absolute path in a record is wrong on every other
|
|
306
314
|
machine, silently. **A files folder is named after the collection or field that indexes it, and
|
|
@@ -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`).
|
|
@@ -111,6 +111,23 @@ first slash. the default namespace has no prefix (`tasks/kickoff`, exactly as al
|
|
|
111
111
|
undeclared prefix reads as a nested id and dangles — `dt check` says so. declaring one is
|
|
112
112
|
`collections.md`.
|
|
113
113
|
|
|
114
|
+
## records stored under another record — the folder follows the owner
|
|
115
|
+
|
|
116
|
+
a collection may declare `storage.under` (`collections.md`): a meeting with a `company` lives in
|
|
117
|
+
that company's folder, one without stays in `data/meetings/`. working with it is unchanged in
|
|
118
|
+
every way that names a record — `list` is the whole collection, `get`/`set`/`rm`/`rename` take
|
|
119
|
+
`meetings/<id>` wherever the file sits, references never carry a folder — and different in one:
|
|
120
|
+
**the owner field moves the file.** `dt set meetings/<id> company=companies/harbor` relocates the
|
|
121
|
+
record into Harbor's folder with the same id and every inbound reference intact; `company=`
|
|
122
|
+
moves it back to the fallback root. so never `mv` one by hand, exactly as for a rename — a file
|
|
123
|
+
under the wrong company is what `check` reports as `placed under … but`, and `dt relocate
|
|
124
|
+
<collection>[/<id>]` (`--dry-run` first) is what moves it to where its field says — refusing whole
|
|
125
|
+
when an owner field dangles, a destination is taken or a source is unpublished. a parent
|
|
126
|
+
holding records in its folder refuses `rm` until they are reassigned; `dt commit <collection>/<id>`
|
|
127
|
+
after a move publishes both paths; `dt revert` of an owner change moves the file back too. before
|
|
128
|
+
the declaration is removed or its path changed: `dt relocate <collection> --to-root`
|
|
129
|
+
(`collections.md` has the order — compile refuses the edit while records would be stranded).
|
|
130
|
+
|
|
114
131
|
## two-way relations — the mirror is generated, and read-only
|
|
115
132
|
|
|
116
133
|
a reference field may declare `x-inverse`: compile GENERATES the field it names on the TARGET
|