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 CHANGED
@@ -1,82 +1,154 @@
1
1
  # dreamteamer
2
2
 
3
- A workspace compiler for coding agents. Module sources compile **explicitly** into `.dreamteamer/`,
4
- the single runtime read surface, and from there into per-harness adapters — Claude Code, Codex, Pi,
5
- Gemini CLI, Cursor. Data is plain files: records are `<id>.<suffix>.<ext>`, ids are paths,
6
- references are `<collection>/<id>`. A write lands on disk; `dreamteamer commit` publishes it, one
7
- commit per repo. Hard validation before disk; nothing hidden.
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 # engine + the `dreamteamer` bin
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 # validate every record
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
- There is a VS Code extension — [dreamteamer-vscode](https://github.com/dreamteamer/dreamteamer-vscode) —
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
- ## Sources, and where they come from
23
+ ## Structured
22
24
 
23
- A module contributes collections, skills, agents, commands, command-bindings, UI views and
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
- ## Attached repos (`repos`) vs modules (`git-modules`)
27
+ ```
28
+ data/meetings/2026/07/kickoff.meeting.md
29
+ ```
30
30
 
31
- Two different lifecycles, deliberately two different homes.
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
- **Modules** are declared in the workspace's `package.json` under `dreamteamer.git-modules` and
34
- restored by `dreamteamer install`. They MUST live in config rather than in records because of a
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
- **Attached repos** are `repos` records under `data/repos/`. They contribute NOTHING to the
39
- workspace no schema, no skills, no UI. A repo record says only where a related git repo lives and
40
- how to get it, and exists so that domain collections can reference `repos/<id>` instead of each
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
- Working trees are materialized **on demand**:
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
- ```bash
47
- dreamteamer repos ensure <id> # clone if missing, print the path; idempotent
48
- dreamteamer repos ensure --all # explicit opt-in, e.g. before going offline
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
- `install` deliberately does not do this. The record count only grows while the fraction any given
52
- session needs only shrinks, so eager restore would make every fresh clone slow, would require every
53
- identity's credentials to be present at install time, and would let one unreachable remote fail the
54
- whole install. Lazy materialization fails only the action you asked for, at the moment you asked.
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
- Path resolution is `<repos-path>/<identity>/<name>`, where `repos-path` is a `package.json`
57
- `dreamteamer` key defaulting to `projects`, and `identity` is optional (omit it for
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
- **`identity` is an opaque path segment to the engine.** A workspace may use it to select a git
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
- **A missing working tree is not a violation.** `dreamteamer check` does not and must not flag it: a
65
- reference to `repos/<id>` resolves because the RECORD exists, and whether the clone is on disk is
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
- ## Domain modules are recipes, not packages
114
+ ## The editor
69
115
 
70
- Anything domain-shaped people, meetings, products, content — belongs in a module, and a generic
71
- version belongs in a recipe a workspace **copies and adapts**. They are deliberately not installable
72
- packages: four workspaces wanted a CRM and all four wanted a different `contacts`, so an import
73
- would force one answer and make every divergence a fork.
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
- better to agree on the shape first.
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
- "name": "dreamteamer",
3
- "version": "0.6.4",
4
- "description": "A workspace compiler for coding agents 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
- "metrics": "node scripts/metrics.mjs",
57
- "metrics:check": "node scripts/metrics.mjs --check",
58
- "layers": "node scripts/layers.mjs"
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
- `users/<id>`. A bare name fails `check`.
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 users, accounts or paths.** Use
77
- `@initiator` / `@me`, and read per-install values from `.env` naming the variable. A hard-coded
78
- `users/<someone>` does not resolve in anyone else's workspace.
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 `users` (because `@me` resolves against it) and `repos` (because `repos ensure`
101
- clones them). Everything else has been ejected on exactly that test — `teams` (nothing resolved a
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), and finally `tasks`, whose only claim to core had been the workflow gate that no
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
- **There is no `collections rename`** it refuses system sources. A rename is `git mv` of the
24
- descriptor + edit `name`/`storage.path`/`suffix` + re-suffix every record, all in one commit.
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 --assignee users/<me> --status todo`), then walk them one at a
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 (`@me` resolves to the current operator). After authoring: compile, then reload the surface.
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: { assignee: { _eq: "@me" } } # operator objects, never a bare value
17
- options: { columns: [name, status, due, run], sort: -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: { assignee: "@me" }` | filters are operator objects: `{ assignee: { _eq: "@me" } }` |
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 filtered to a named user | use `@me`; a hard-coded id breaks elsewhere |
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, `users` and
67
- `repos`, and deliberately nothing else.
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: `npm run --silent dt -- tasks list --assignee
88
- users/<user> --status todo`. ⚠ the current user is a record in `data/users/` whose id is
89
- `slug(git config user.name)`; when those disagree the inbox comes back **empty with no error**.
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/users/x.user.md`) | refs are `<collection>/<id>`; anything else fails check |
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: users/ada
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 = value.slice(value.indexOf('/') + 1);
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
- const slash = value.indexOf('/');
141
- if (slash < 1) return flag(file, `${fieldPath.join('.')}: reference "${value}" is not <collection>/<id>`);
142
- const coll = value.slice(0, slash);
143
- const id = value.slice(slash + 1);
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