dreamteamer 0.6.4 → 0.8.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 +123 -51
- package/package.json +62 -58
- package/skills/building-dreamteamer/SKILL.md +10 -7
- package/skills/building-dreamteamer/references/collections.md +32 -2
- package/skills/building-dreamteamer/references/commands.md +1 -1
- package/skills/building-dreamteamer/references/ui-views.md +10 -5
- package/skills/using-dreamteamer/SKILL.md +7 -6
- package/skills/using-dreamteamer/references/records.md +18 -1
- package/src/check.js +12 -6
- package/src/cli.js +7 -1
- package/src/collections-cli.js +28 -2
- package/src/compile.js +74 -7
- package/src/harnesses.js +29 -8
- package/src/init.js +20 -19
- package/src/namespace.js +181 -0
- package/src/runtime.js +29 -3
- package/src/schema-ops.js +260 -11
- package/src/server.js +13 -14
- package/src/store.js +56 -20
- package/collections/users.collection.yaml +0 -21
package/README.md
CHANGED
|
@@ -1,82 +1,154 @@
|
|
|
1
1
|
# dreamteamer
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
**Structured, modular memory for coding agents.**
|
|
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.
|
|
9
|
+
|
|
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.
|
|
8
12
|
|
|
9
13
|
```bash
|
|
10
|
-
npm i dreamteamer
|
|
14
|
+
npm i dreamteamer
|
|
11
15
|
npx dreamteamer init # scaffold a workspace
|
|
12
16
|
npx dreamteamer compile # sources → .dreamteamer (+ harness adapters)
|
|
13
|
-
npx dreamteamer check #
|
|
17
|
+
npx dreamteamer check # prove every record and every link is intact
|
|
14
18
|
npx dreamteamer help # the full command surface
|
|
15
19
|
```
|
|
16
20
|
|
|
17
|
-
|
|
18
|
-
which loads the engine **your workspace pins**, so the editor, the CLI and any agent session are
|
|
19
|
-
provably running the same code.
|
|
21
|
+
Apache-2.0. No server, no account, no telemetry.
|
|
20
22
|
|
|
21
|
-
##
|
|
23
|
+
## Structured
|
|
22
24
|
|
|
23
|
-
A
|
|
24
|
-
collection templates. Modules are discovered over three channels, in precedence order: inline
|
|
25
|
-
`modules/*`, then `git_modules/*`, then npm dependencies. Sources live **flat at a module root** —
|
|
26
|
-
`modules/crm/skills/`, beside `package.json` — and an unknown folder at a module root is a compile
|
|
27
|
-
error rather than a silent skip.
|
|
25
|
+
A record is a file. That's the whole trick.
|
|
28
26
|
|
|
29
|
-
|
|
27
|
+
```
|
|
28
|
+
data/meetings/2026/07/kickoff.meeting.md
|
|
29
|
+
```
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
```yaml
|
|
32
|
+
---
|
|
33
|
+
title: Kickoff
|
|
34
|
+
date: 2026-07-14
|
|
35
|
+
attendees: [contacts/ada, contacts/lin]
|
|
36
|
+
project: projects/apollo
|
|
37
|
+
---
|
|
38
|
+
Ada walked through the constraints. Lin owns the spec by Friday.
|
|
39
|
+
```
|
|
32
40
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
genuine bootstrap ordering: a fresh clone has no `.dreamteamer`, therefore no compiled schemas,
|
|
36
|
-
therefore no readable records — so module clones have to be restorable before anything can be read.
|
|
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.
|
|
37
43
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
inventing its own url/ref/identity fields. Because they are not needed at compile time, they get to
|
|
42
|
-
be data — which buys hard validation, the record CLI verbs, and history for free.
|
|
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**.
|
|
43
47
|
|
|
44
|
-
|
|
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:
|
|
45
50
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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
|
+
## Modular
|
|
67
|
+
|
|
68
|
+
**Data and skills are the new app structure.** A coding agent with the right skills over the right
|
|
69
|
+
data is arbitrary functionality — but composing that with no module system is where most setups stall.
|
|
70
|
+
|
|
71
|
+
So dreamteamer doesn't invent one. **It uses npm.**
|
|
72
|
+
|
|
73
|
+
`node_modules` is battle-tested, universally adopted, and already sitting in nearly every
|
|
74
|
+
coding-agent setup. A module contributes collections, skills, agents, commands, command-bindings and
|
|
75
|
+
UI views — and skills and agents are treated as exactly what they are: **memory that loads into
|
|
76
|
+
context**, living in the same module structure as everything else, in a standard your tooling already
|
|
77
|
+
understands.
|
|
78
|
+
|
|
79
|
+
Three channels, one shape:
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
modules/<name>/ # lives in this repo
|
|
83
|
+
git_modules/<name>/ # lives in its own repo
|
|
84
|
+
node_modules/<name>/ # published package
|
|
49
85
|
```
|
|
50
86
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
87
|
+
Precedence runs top to bottom, so a local copy shadows a published one — which is how you develop a
|
|
88
|
+
module and use it in the same workspace at the same time.
|
|
89
|
+
|
|
90
|
+
Sources live **flat at a module root** — `modules/crm/skills/`, beside `package.json` — and a folder
|
|
91
|
+
at a module root that isn't a known kind is a compile error rather than a silent skip.
|
|
92
|
+
|
|
93
|
+
### Modules are not rigid
|
|
94
|
+
|
|
95
|
+
This is the part that differs from npm on purpose.
|
|
96
|
+
|
|
97
|
+
Installing a module into a workspace that already has opinions — its own idea of what a `contact` is —
|
|
98
|
+
is a **negotiation, not an overwrite**. Four workspaces wanted a CRM and all four wanted a different
|
|
99
|
+
`contacts`. A hard import would force one answer and make every divergence a fork.
|
|
100
|
+
|
|
101
|
+
Two same-name collections is a compile error that names both descriptors and tells you the move:
|
|
102
|
+
declare `extends: <module>/<collection>` and overlay only what differs. Because every schema is one
|
|
103
|
+
small YAML file, adapting is cheap — read it, change what doesn't fit, and the diff shows exactly what
|
|
104
|
+
you agreed to.
|
|
55
105
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
`<repos-path>/<name>`). A record's `path` field overrides the derivation entirely.
|
|
106
|
+
So domain modules are **recipes you copy and adapt, not packages you install**, and divergence is the
|
|
107
|
+
normal case rather than a failure.
|
|
59
108
|
|
|
60
|
-
|
|
61
|
-
identity — via `~/.gitconfig` `includeIf` rules keyed on the path, for example — but that resolution
|
|
62
|
-
happens outside the engine, which only joins it into a path.
|
|
109
|
+
## Every harness, one source
|
|
63
110
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
irrelevant to referential integrity. Presence is reported by `dreamteamer status`.
|
|
111
|
+
`compile` writes `.dreamteamer/` — the single runtime read surface — and from there into per-harness
|
|
112
|
+
adapters: Claude Code, Codex, Pi, Gemini CLI, Cursor. Author a skill once; every agent you run sees it.
|
|
67
113
|
|
|
68
|
-
##
|
|
114
|
+
## The editor
|
|
69
115
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
116
|
+
[dreamteamer-vscode](https://github.com/dreamteamer/dreamteamer-vscode) gives you tables, boards,
|
|
117
|
+
calendars, maps, forms and a data-model designer over the same files — and it loads **the engine your
|
|
118
|
+
workspace pins**, so the editor, the CLI and any agent session are provably running the same code.
|
|
119
|
+
|
|
120
|
+
## Docs
|
|
121
|
+
|
|
122
|
+
This is an agent-native tool, so its documentation is shipped as skills the agent loads on demand —
|
|
123
|
+
and you can read them like any other file:
|
|
124
|
+
|
|
125
|
+
- [`skills/using-dreamteamer`](skills/using-dreamteamer) — the map: collections, conventions, the CLI,
|
|
126
|
+
how records work
|
|
127
|
+
- [`skills/building-dreamteamer`](skills/building-dreamteamer) — authoring: collections, skills,
|
|
128
|
+
agents, commands, UI views, and which of those a given request should become
|
|
129
|
+
- [`docs/repos-and-modules.md`](docs/repos-and-modules.md) — attached repos vs modules, and why they
|
|
130
|
+
have different homes
|
|
131
|
+
- [`docs/namespaces-blast-radius.md`](docs/namespaces-blast-radius.md) — scoping collections under a
|
|
132
|
+
namespace (`health/doctors`), what it costs consumers, and why the default namespace is transparent
|
|
133
|
+
- [`UPDATING.md`](UPDATING.md) — what to do when upgrading, one section per release
|
|
134
|
+
|
|
135
|
+
## What it isn't
|
|
136
|
+
|
|
137
|
+
Not a database — records are files and git is the history. Not a cloud service — there is no server
|
|
138
|
+
and no account. Not a note-taking app — it's the layer underneath one.
|
|
139
|
+
|
|
140
|
+
And it is **not** for data that needs row-level access control, field-level encryption, or provable
|
|
141
|
+
erasure. Git cannot do those, and pretending otherwise is how people get hurt. This is for
|
|
142
|
+
human-scale structured knowledge: thousands of records, not millions.
|
|
74
143
|
|
|
75
144
|
## Contributing
|
|
76
145
|
|
|
77
146
|
Issues are welcome. For anything larger than a typo, please open a discussion before a pull request —
|
|
78
|
-
this is a small, deliberately lean codebase (`npm run metrics` enforces size budgets), and it's
|
|
79
|
-
|
|
147
|
+
this is a small, deliberately lean codebase (`npm run metrics` enforces size budgets), and it's better
|
|
148
|
+
to agree on the shape first.
|
|
149
|
+
|
|
150
|
+
`npm run verify` is the gate: import-layer direction, size budgets, and the test suite (tiers 1+2,
|
|
151
|
+
zero dependencies, a few seconds). See [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
80
152
|
|
|
81
153
|
## License
|
|
82
154
|
|
package/package.json
CHANGED
|
@@ -1,60 +1,64 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
2
|
+
"name": "dreamteamer",
|
|
3
|
+
"version": "0.8.0",
|
|
4
|
+
"description": "A workspace compiler for coding agents \u2014 schema-validated records as plain files over git, compiled into every harness",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"author": "Gilad Khen <giladkhen@gmail.com>",
|
|
7
|
+
"homepage": "https://github.com/dreamteamer/dreamteamer#readme",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/dreamteamer/dreamteamer.git"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/dreamteamer/dreamteamer/issues"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"agent",
|
|
17
|
+
"coding-agent",
|
|
18
|
+
"claude-code",
|
|
19
|
+
"workspace",
|
|
20
|
+
"compiler",
|
|
21
|
+
"cli",
|
|
22
|
+
"yaml",
|
|
23
|
+
"markdown",
|
|
24
|
+
"json-schema",
|
|
25
|
+
"git"
|
|
26
|
+
],
|
|
27
|
+
"type": "module",
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=20"
|
|
30
|
+
},
|
|
31
|
+
"bin": {
|
|
32
|
+
"dreamteamer": "./bin/dreamteamer.js"
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"NOTICE",
|
|
36
|
+
"bin",
|
|
37
|
+
"src",
|
|
38
|
+
"collections",
|
|
39
|
+
"skills",
|
|
40
|
+
"agents",
|
|
41
|
+
"commands",
|
|
42
|
+
"command-bindings",
|
|
43
|
+
"ui-views",
|
|
44
|
+
"collection-templates"
|
|
45
|
+
],
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"ajv": "^8.17.1",
|
|
48
|
+
"ajv-formats": "^3.0.1",
|
|
49
|
+
"express": "^5.2.1",
|
|
50
|
+
"js-yaml": "^4.1.0"
|
|
51
|
+
},
|
|
52
|
+
"dreamteamer": {
|
|
53
|
+
"title": "System"
|
|
54
|
+
},
|
|
55
|
+
"scripts": {
|
|
56
|
+
"test": "node scripts/test.mjs",
|
|
57
|
+
"test:unit": "node scripts/test.mjs --unit",
|
|
58
|
+
"test:watch": "node --watch scripts/test.mjs --unit",
|
|
59
|
+
"metrics": "node scripts/metrics.mjs",
|
|
60
|
+
"metrics:check": "node scripts/metrics.mjs --check",
|
|
61
|
+
"layers": "node scripts/layers.mjs",
|
|
62
|
+
"verify": "node scripts/layers.mjs && node scripts/metrics.mjs --check && node scripts/test.mjs"
|
|
63
|
+
}
|
|
60
64
|
}
|
|
@@ -62,7 +62,7 @@ These were duplicated across seven skills; they are true for all of them.
|
|
|
62
62
|
conversation already in progress. A new command, agent or skill is available in the **next**
|
|
63
63
|
session. Say so rather than letting the operator wonder.
|
|
64
64
|
6. **References are qualified** — `skills/<id>`, `agents/<id>`, `commands/<id>`, `collections/<id>`,
|
|
65
|
-
|
|
65
|
+
and `<collection>/<id>` for any record. A bare name fails `check`.
|
|
66
66
|
7. **Never edit generated output.** `.dreamteamer/`, `.claude/`, `.agents/`, `.cursor/` are all
|
|
67
67
|
overwritten and pruned on the next compile. If you found the thing you want to change in one of
|
|
68
68
|
those, you are in the wrong file.
|
|
@@ -73,9 +73,11 @@ These were duplicated across seven skills; they are true for all of them.
|
|
|
73
73
|
9. **Never duplicate a procedure across records.** A command body that restates a skill, an agent
|
|
74
74
|
body that inlines its skill's steps, a command that re-types another command's prompt — each is two
|
|
75
75
|
copies that drift. Reference the one that owns it.
|
|
76
|
-
10. **Module-shipped entities must not name a workspace's own
|
|
77
|
-
|
|
78
|
-
`
|
|
76
|
+
10. **Module-shipped entities must not name a workspace's own people, accounts or paths.** Read
|
|
77
|
+
per-install values from `.env` naming the variable, and leave who-did-what to a collection the
|
|
78
|
+
workspace owns. A hard-coded `contacts/<someone>` does not resolve in anyone else's workspace.
|
|
79
|
+
⚠ **There is no `@me` since 0.8.0** — it expanded to `users/<slug>`, and `users` is gone. A
|
|
80
|
+
ui-view filter still using it is a compile error, not a view that quietly shows nothing.
|
|
79
81
|
|
|
80
82
|
## the loop
|
|
81
83
|
|
|
@@ -97,11 +99,12 @@ a collection about people, meetings, tasks, products, content — belongs in a m
|
|
|
97
99
|
version of it belongs in the `recipes` repo rather than here.
|
|
98
100
|
|
|
99
101
|
**The test is: does the ENGINE read it?** Core's collections are the entity kinds the compiler itself
|
|
100
|
-
materializes, plus `
|
|
101
|
-
|
|
102
|
+
materializes, plus `repos` (because `repos ensure` clones them). Everything else has been ejected on
|
|
103
|
+
exactly that test — `teams` (nothing resolved a
|
|
102
104
|
team), `mounts` (a one-implementation adapter enum over an `.env` key), `module-registries` (zero
|
|
103
105
|
readers), `workflows`/`workflow-runs`/`workflow-triggers`/`cursors` and `migrations`/`migration-runs`
|
|
104
|
-
(measured unused),
|
|
106
|
+
(measured unused), `users` (0.8.0 — its justification was circular: core because `@me` resolved
|
|
107
|
+
against it, and `@me` existed because it was core), and finally `tasks`, whose only claim to core had been the workflow gate that no
|
|
105
108
|
longer exists. `npm run metrics` in the engine holds the budgets that keep this honest.
|
|
106
109
|
|
|
107
110
|
## common mistakes
|
|
@@ -8,6 +8,7 @@ One descriptor file: `modules/<module>/collections/<name>.collection.yaml`. The
|
|
|
8
8
|
| goal | how |
|
|
9
9
|
|---|---|
|
|
10
10
|
| new collection from a template | `dt collections add --name research-docs --template docs` |
|
|
11
|
+
| move one into a namespace | `dt collections rename doctors health/doctors` (or `doctors --namespace health`) |
|
|
11
12
|
| templateless | `dt collections add --name <n>` — emits a minimal compilable schema |
|
|
12
13
|
| add a field | `dt <collection> add-field --name urgent --type boolean --default-value false` |
|
|
13
14
|
| change / drop a field | `dt <collection> update-field …` · `remove-field --name <f>` |
|
|
@@ -20,8 +21,37 @@ or a bare collection name for a reference into it. `--required true` widens `req
|
|
|
20
21
|
|
|
21
22
|
⚠ **The meta verbs write the WORKSPACE module only.** To change a field on a collection another
|
|
22
23
|
module owns, either edit that module's descriptor by hand or add an `extends:` overlay.
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
**`dt collections rename <old> <new>`** moves the descriptor, the records, the record filenames and
|
|
25
|
+
every inbound reference in ONE commit — including `x-reference` targets in other descriptors and any
|
|
26
|
+
ui-view pointing at it. `<old> --namespace <ns>` is sugar for moving it into a namespace under the same
|
|
27
|
+
bare name. It refuses a compiled source, a module-owned collection, a taken name, and an undeclared
|
|
28
|
+
target namespace; a refusal leaves nothing half-moved. Two things it deliberately does NOT overrule,
|
|
29
|
+
because both are authored choices: a `storage.path` you set by hand (the records stay put, and it says
|
|
30
|
+
so) and a `storage.suffix` that is not the singular of the old name.
|
|
31
|
+
|
|
32
|
+
## namespaces — scoping a collection under a folder
|
|
33
|
+
|
|
34
|
+
A collection name may carry a slash-delimited namespace, and it becomes real directory nesting:
|
|
35
|
+
|
|
36
|
+
| declare in the workspace `package.json` | create it | lands in | referenced as |
|
|
37
|
+
|---|---|---|---|
|
|
38
|
+
| `"namespaces": ["health"]` | `dt collections add --namespace health --name doctors` | `data/health/doctors/` | `health/doctors/dana-levi` |
|
|
39
|
+
|
|
40
|
+
- **The default namespace is the empty prefix.** `tasks` stays `data/tasks/` and `tasks/kickoff`, so
|
|
41
|
+
common entities need no prefix and adopting namespaces migrates nothing. `default` is RESERVED —
|
|
42
|
+
there is never a second spelling for one collection.
|
|
43
|
+
- ⚠ **The namespace MUST be declared before the collection compiles.** An id is also a slash path
|
|
44
|
+
(`meetings/2026/07/kickoff`), so `a/b/c` is ambiguous without the declared set; an undeclared prefix
|
|
45
|
+
is a compile error rather than a reference that silently names a different collection.
|
|
46
|
+
- `--namespace health --name doctors` and `--name health/doctors` are the same thing. The descriptor
|
|
47
|
+
lands at `collections/health/doctors.collection.yaml`, mirroring the runtime; the `suffix` comes off
|
|
48
|
+
the bare name (`<id>.doctor.md`).
|
|
49
|
+
- `x-reference: health/doctors`, `disable: "<module>/health/doctors"` and every record verb all take the
|
|
50
|
+
QUALIFIED name — it is the collection's identity everywhere.
|
|
51
|
+
- Nested namespaces work (`work/clients`), longest declared prefix wins.
|
|
52
|
+
- ⚠ **No collection may store records inside another's folder** — a namespace folder cannot itself be a
|
|
53
|
+
collection root. compile refuses it, because the outer collection would index the inner one's records
|
|
54
|
+
as its own.
|
|
25
55
|
|
|
26
56
|
## `templates:` — a live shared field set
|
|
27
57
|
|
|
@@ -13,7 +13,7 @@ description: triage every open task assigned to me, one at a time
|
|
|
13
13
|
argument-hint: "[assignee]"
|
|
14
14
|
---
|
|
15
15
|
load this workspace's tasks skill. list my open tasks
|
|
16
|
-
(`npm run --silent dt -- tasks list --
|
|
16
|
+
(`npm run --silent dt -- tasks list --status todo`), then walk them one at a
|
|
17
17
|
time: restate it, ask me to keep / reassign / drop, apply the decision with `tasks set`.
|
|
18
18
|
done when the list is empty or I say stop.
|
|
19
19
|
```
|
|
@@ -5,7 +5,7 @@ route plus the id of an already-registered layout, plus how to shape the data. N
|
|
|
5
5
|
|
|
6
6
|
The surface reads compiled ui-view records at boot: `nav` becomes a sidebar entry, `path` becomes a
|
|
7
7
|
live route, `target: list` renders the named `layout` over the collection with `filter`/`options`
|
|
8
|
-
applied
|
|
8
|
+
applied. After authoring: compile, then reload the surface.
|
|
9
9
|
|
|
10
10
|
```yaml
|
|
11
11
|
path: /inbox
|
|
@@ -13,10 +13,14 @@ nav: { label: Inbox, icon: inbox, order: 1 }
|
|
|
13
13
|
target: list
|
|
14
14
|
collection: collections/tasks
|
|
15
15
|
layout: table
|
|
16
|
-
filter: {
|
|
17
|
-
options: { columns: [name, status, due
|
|
16
|
+
filter: { status: { _eq: todo } } # operator objects, never a bare value
|
|
17
|
+
options: { columns: [name, status, due], sort: -due }
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
+
⚠ **`@me` no longer exists** — it was removed with the `users` collection in 0.8.0, and a filter using
|
|
21
|
+
it is a compile error rather than a view that quietly shows nothing. Filter on a field this workspace
|
|
22
|
+
owns; where a person is genuinely the axis, the workspace ships its own collection of people.
|
|
23
|
+
|
|
20
24
|
| field | required | notes |
|
|
21
25
|
|---|---|---|
|
|
22
26
|
| `path` | yes | the route — `/inbox`, `/views/meetings/recent` |
|
|
@@ -53,7 +57,8 @@ through the same compile gate.
|
|
|
53
57
|
|---|---|
|
|
54
58
|
| a `layout` id you assumed exists | compile validates it only for `target: list`; otherwise the view renders nothing |
|
|
55
59
|
| bare `collection: tasks` | qualified refs only |
|
|
56
|
-
| `filter: {
|
|
60
|
+
| `filter: { status: "todo" }` | filters are operator objects: `{ status: { _eq: todo } }` |
|
|
61
|
+
| a filter using `@me` | gone in 0.8.0 with `users` — compile refuses it by name |
|
|
57
62
|
| a column the schema does not have | dropped silently — the row loses that value with no error |
|
|
58
63
|
| a ui-view that restates the built-in fallback | a record to maintain for zero gain |
|
|
59
|
-
| a module ui-view
|
|
64
|
+
| a module ui-view naming one person | a hard-coded id resolves in no other workspace |
|
|
@@ -63,8 +63,8 @@ when you're not sure the runtime is fresh.
|
|
|
63
63
|
| the workspace lacks the capability entirely | `building-dreamteamer` → `references/before-you-build.md` |
|
|
64
64
|
|
|
65
65
|
Domain work — meetings, contacts, tasks, content, design — is owned by the **module** that ships those
|
|
66
|
-
collections, not by core. Read that module's own skills. Core knows about entity kinds
|
|
67
|
-
|
|
66
|
+
collections, not by core. Read that module's own skills. Core knows about entity kinds and `repos`,
|
|
67
|
+
and deliberately nothing else — including nothing about people. There is no `users` collection.
|
|
68
68
|
|
|
69
69
|
## conventions
|
|
70
70
|
|
|
@@ -84,9 +84,10 @@ collections, not by core. Read that module's own skills. Core knows about entity
|
|
|
84
84
|
- **validate after bulk edits**: `npm run check` reports violations and never modifies files.
|
|
85
85
|
- workspace-level rules live in `CLAUDE.md`, and a workspace's decision log (where one exists) wins
|
|
86
86
|
over older documents.
|
|
87
|
-
- **session greeting** — surface the operator's inbox
|
|
88
|
-
|
|
89
|
-
|
|
87
|
+
- **session greeting** — surface the operator's inbox from whatever collection this workspace uses for
|
|
88
|
+
work, e.g. `npm run --silent dt -- tasks list --status todo`. ⚠ **there is no `users` collection and
|
|
89
|
+
no `@me`** (both removed in 0.8.0); read the operator from `git config user.name` at the point you
|
|
90
|
+
need one, and never filter on a person unless this workspace owns a collection of them.
|
|
90
91
|
|
|
91
92
|
## common mistakes
|
|
92
93
|
|
|
@@ -95,6 +96,6 @@ collections, not by core. Read that module's own skills. Core knows about entity
|
|
|
95
96
|
| editing something under `.dreamteamer/` | generated + gitignored; the change vanishes on the next compile |
|
|
96
97
|
| changing a source and not compiling | the harness and `check` still read the stale runtime |
|
|
97
98
|
| hand-writing a record the CLI could add | skips validation, id generation and defaults |
|
|
98
|
-
| bare refs (`ada`, `data/
|
|
99
|
+
| bare refs (`ada`, `data/contacts/x.contact.md`) | refs are `<collection>/<id>`; anything else fails check |
|
|
99
100
|
| assuming a write was committed | it was not, unless `auto-commit` is on — `dt status` says what is pending |
|
|
100
101
|
| `git add -A` in a shared tree | steals another session's uncommitted work, invisibly |
|
|
@@ -68,12 +68,29 @@ fields, the body is the single `x-body: true` field):
|
|
|
68
68
|
---
|
|
69
69
|
title: Fix login flow
|
|
70
70
|
status: todo
|
|
71
|
-
assignee:
|
|
71
|
+
assignee: contacts/ada
|
|
72
72
|
due: '2026-07-28'
|
|
73
73
|
---
|
|
74
74
|
Users report the login button does nothing on mobile.
|
|
75
75
|
```
|
|
76
76
|
|
|
77
|
+
## namespaced collections
|
|
78
|
+
|
|
79
|
+
A collection may be scoped under a namespace declared in the workspace `package.json`
|
|
80
|
+
(`dreamteamer.namespaces`). Everything about working with its records is unchanged except that the
|
|
81
|
+
QUALIFIED name is the collection's name everywhere:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
dt health/doctors add --name "Dana Levi" # → data/health/doctors/dana-levi.doctor.md
|
|
85
|
+
dt health/visits add --name Checkup --date 2026-03-04 --doctor health/doctors/dana-levi
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
- a reference is still `<collection>/<id>` — `health/doctors/dana-levi` is the collection
|
|
89
|
+
`health/doctors` and the id `dana-levi`.
|
|
90
|
+
- the **default namespace has no prefix**: `tasks/kickoff` in `data/tasks/`, exactly as always.
|
|
91
|
+
- ⚠ a namespace only exists if it is DECLARED. Without the declaration the same string reads as the
|
|
92
|
+
collection `health` with a nested id, so it dangles — `dt check` says so.
|
|
93
|
+
|
|
77
94
|
## the hard rules
|
|
78
95
|
|
|
79
96
|
**never hand-rename or `mv` a record file** — the id IS the path, so a rename silently dangles
|
package/src/check.js
CHANGED
|
@@ -6,7 +6,8 @@ import path from 'node:path';
|
|
|
6
6
|
import Ajv from 'ajv';
|
|
7
7
|
import addFormats from 'ajv-formats';
|
|
8
8
|
import { parseRecord, patternRe, fmtAjvError, unknownFields, walk, EXT } from './records.js';
|
|
9
|
-
import { NO_RUNTIME, loadDescriptors, runtimeDir } from './runtime.js';
|
|
9
|
+
import { NO_RUNTIME, loadDescriptors, runtimeDir, namespaces as compiledNamespaces } from './runtime.js';
|
|
10
|
+
import { parseRef } from './namespace.js';
|
|
10
11
|
|
|
11
12
|
export function check({ root }) {
|
|
12
13
|
const RUNTIME = runtimeDir(root);
|
|
@@ -25,6 +26,9 @@ export function check({ root }) {
|
|
|
25
26
|
console.error(`✖ ${NO_RUNTIME}`);
|
|
26
27
|
return 2;
|
|
27
28
|
}
|
|
29
|
+
// Off the manifest, like the descriptors themselves — `check` is in the record layer and must not
|
|
30
|
+
// learn what a workspace package.json is (see the split in CLAUDE.md).
|
|
31
|
+
const namespaces = compiledNamespaces(root);
|
|
28
32
|
|
|
29
33
|
// ---- index all records: collection -> Map<id, filePath> ------------------------
|
|
30
34
|
const index = new Map();
|
|
@@ -122,7 +126,8 @@ export function check({ root }) {
|
|
|
122
126
|
const self = `${name}/${id}`;
|
|
123
127
|
for (const value of valuesAt(fields, fieldPath)) {
|
|
124
128
|
if (typeof value !== 'string' || value.startsWith('@')) continue;
|
|
125
|
-
const targetId =
|
|
129
|
+
const targetId = parseRef(value, namespaces)?.id;
|
|
130
|
+
if (targetId === undefined) continue; // already flagged as malformed
|
|
126
131
|
const targetFields = parsed.get(target)?.get(targetId);
|
|
127
132
|
if (!targetFields) continue; // already flagged as dangling
|
|
128
133
|
const back = [...valuesAt(targetFields, [inverse])];
|
|
@@ -137,10 +142,11 @@ export function check({ root }) {
|
|
|
137
142
|
function checkRef(file, fieldPath, value, target, softTargets) {
|
|
138
143
|
if (typeof value !== 'string') return;
|
|
139
144
|
if (value.startsWith('@')) return; // runtime tokens (@me, @initiator) are legal
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
const
|
|
143
|
-
|
|
145
|
+
// The SAME parser the store writes through (src/namespace.js) — `check` disagreeing with the
|
|
146
|
+
// write path about where a namespace ends would flag valid records and pass invalid ones.
|
|
147
|
+
const ref = parseRef(value, namespaces);
|
|
148
|
+
if (!ref) return flag(file, `${fieldPath.join('.')}: reference "${value}" is not <collection>/<id>`);
|
|
149
|
+
const { collection: coll, id } = ref;
|
|
144
150
|
if (target !== '*' && coll !== target) {
|
|
145
151
|
return flag(file, `${fieldPath.join('.')}: reference "${value}" should target collection "${target}"`);
|
|
146
152
|
}
|
package/src/cli.js
CHANGED
|
@@ -55,8 +55,14 @@ repo attachment (working trees are materialized ON DEMAND, never at install):
|
|
|
55
55
|
repos ensure --all [--json] (explicit opt-in: everything, e.g. before going offline)
|
|
56
56
|
|
|
57
57
|
meta verbs (schema operations — write SOURCES through a compile gate, never the runtime):
|
|
58
|
-
collections add --name <name> [--template docs|entity]
|
|
58
|
+
collections add --name <name> [--namespace <ns>] [--template docs|entity]
|
|
59
|
+
(--namespace health --name doctors === --name health/doctors; the
|
|
60
|
+
namespace must already be declared in dreamteamer.namespaces, and
|
|
61
|
+
records land in data/<ns>/<name>/)
|
|
59
62
|
collections rm <name> [--force] (--force required if it still has records)
|
|
63
|
+
collections rename <old> <new> (or <old> --namespace <ns> to move it into one)
|
|
64
|
+
moves the descriptor AND the records, re-suffixes files when the
|
|
65
|
+
suffix was derived, rewrites every inbound reference, ONE commit
|
|
60
66
|
<collection> add-field --name <field> --type <type> [--options a,b] [--default-value v] [--required true]
|
|
61
67
|
[--description "what this field means"]
|
|
62
68
|
types: string text markdown boolean number integer date datetime
|