dreamteamer 0.9.1 → 0.12.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
@@ -63,6 +63,30 @@ The shape of a record is deliberately dull, because dull is what survives:
63
63
  - a write lands on disk; `dreamteamer commit` publishes it, one commit per repo
64
64
  - schemas are JSON Schema in a YAML file, one per collection
65
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` — plus `${workspaceFolder}` and `${userHome}`.
77
+ One verb renders them:
78
+
79
+ ```bash
80
+ npx dreamteamer resolve '${env:FILES_FOLDER}/x' # → /Volumes/annex/x
81
+ npx dreamteamer resolve <collection>/<id> <field> # render what a record already holds
82
+ ```
83
+
84
+ **Templates are ordinary data — write them literally; nothing substitutes until `resolve` is
85
+ called.** `get`, `list`, `check` and every harness see the template verbatim, which is exactly what
86
+ makes the record mean the same thing on every machine instead of quietly meaning two things. An
87
+ undeclared key and a declared-but-absent one are different errors, and `compile` warns — by name,
88
+ never by value — when a declared var has nothing behind it here.
89
+
66
90
  ## Modular
67
91
 
68
92
  **Data and skills are the new app structure.** A coding agent with the right skills over the right
@@ -11,6 +11,17 @@ schema:
11
11
  description:
12
12
  type: string
13
13
  description: What kind of thing this collection holds, in one line.
14
+ use_when:
15
+ type: string
16
+ description: >-
17
+ WHEN to reach for this collection, in one clause — rendered into the orientation block every
18
+ agent session loads. OPTIONAL and usually absent: for most collections the trigger IS the
19
+ description (`contacts` = a person; you use it when you have a person), and a restatement
20
+ there costs every session tokens while diluting the few that carry real information. The
21
+ test: author this only when an agent that FULLY UNDERSTANDS the description would still not
22
+ know to reach for the collection. It spans both acts — read ("you are about to diagnose a
23
+ defect — search here first") and write ("a day needs planning"). NOT a place for procedure:
24
+ a `how` belongs in the module's skill, this field holds a `when`.
14
25
  title:
15
26
  type: string
16
27
  description: What to call this collection in the nav and page headers. DERIVED from `name` by title-casing when absent — author it only when that is wrong (`ui-views` → `UI Views`).
@@ -66,6 +77,13 @@ schema:
66
77
  type: array
67
78
  items: { type: string }
68
79
  description: The columns a list view shows by default.
80
+ sort_field:
81
+ type: string
82
+ description: >-
83
+ Which field carries MANUAL order — the one a drag writes. The field must be declared by this
84
+ collection's own schema, and holds a fractional index (`dt <collection> move`), never an
85
+ integer: renumbering is a multi-file commit against git. A surface offers dragging only while
86
+ it is sorted by this field, because a handle that reorders nothing is a lie.
69
87
  icon:
70
88
  type: string
71
89
  description: material-symbols-outlined icon name, drawn in the nav and page header. The VS Code tree maps it to the nearest codicon — an unmapped name falls back to a generic cylinder, so pick one that is already mapped or add the row.
@@ -1,4 +1,7 @@
1
1
  name: repos
2
+ description: >-
3
+ A git repository this workspace knows about — where it lives and how a working tree is
4
+ materialized on demand.
2
5
  # An external git repo attached to this workspace. Owns CLONE LIFECYCLE ONLY — a repo record
3
6
  # never contributes schema, skills or UI (that is what a module is, declared in package.json
4
7
  # `dreamteamer.git-modules`, because modules must be restorable BEFORE compile can run).
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dreamteamer",
3
- "version": "0.9.1",
4
- "description": "A workspace compiler for coding agents \u2014 schema-validated records as plain files over git, compiled into every harness",
3
+ "version": "0.12.0",
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>",
7
7
  "homepage": "https://github.com/dreamteamer/dreamteamer#readme",
@@ -47,6 +47,7 @@
47
47
  "ajv": "^8.17.1",
48
48
  "ajv-formats": "^3.0.1",
49
49
  "express": "^5.2.1",
50
+ "fractional-indexing": "^4.0.0",
50
51
  "js-yaml": "^4.1.0"
51
52
  },
52
53
  "dreamteamer": {
@@ -37,7 +37,7 @@ Three tie-breakers worth internalising, because they are the ones that go wrong:
37
37
  - **a multi-step process is a CHAIN OF COMMANDS, not an entity.** There is no workflow kind: a
38
38
  `workflows` collection with run records, triggers and an executor existed until 2026-07-31 and was
39
39
  removed after three days of measurement showed the work being done by a command chain instead. Write
40
- one command per step, bind each to its collection so `dt commands for <ref>` shows what applies, and
40
+ one command per step, bind each to its collection so `dt commands <ref>` shows what applies, and
41
41
  a command whose body invokes the others in order if the sequence needs a name. The record's own state
42
42
  is the progress marker — which is what made the run records redundant.
43
43
 
@@ -54,7 +54,7 @@ These were duplicated across seven skills; they are true for all of them.
54
54
  makes the id lie.
55
55
  3. **The meta-descriptor IS the spec.** Every kind is itself a collection:
56
56
  `.dreamteamer/collections/<kind>.collection.yaml` lists every key it may carry with its
57
- allowed values. Read that, plus a real one (`dt <kind> get <id>`), instead of learning the shape
57
+ allowed values. Read that, plus a real one (`dt get <kind>/<id>`), instead of learning the shape
58
58
  from prose. Prose drifts; the descriptor cannot.
59
59
  4. **`npm run compile`, then `npm run check`.** Compile materializes the runtime and the harness
60
60
  adapters; check validates refs and shapes and never modifies files. Neither is optional.
@@ -66,10 +66,10 @@ These were duplicated across seven skills; they are true for all of them.
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.
69
- 8. **The CLI refuses system-stored records on purpose.** `dt skills set …` will not work; edit the
69
+ 8. **The CLI refuses system-stored records on purpose.** `dt set skills/<id> …` will not work; edit the
70
70
  module source and compile. The exceptions are the meta verbs that write sources *through* a
71
- compile gate — `collections add`, `<collection> add-field`, `ui-views add|set` — which exist so
72
- an uncompilable source can never land in history.
71
+ compile gate — `schema add-collection`, `schema add-field <collection>`, `schema add-view|set-view` —
72
+ which exist so an uncompilable source can never land in history.
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.
@@ -99,7 +99,7 @@ a collection about people, meetings, tasks, products, content — belongs in a m
99
99
  version of it belongs in the `recipes` repo rather than here.
100
100
 
101
101
  **The test is: does the ENGINE read it?** Core's collections are the entity kinds the compiler itself
102
- materializes, plus `repos` (because `repos ensure` clones them). Everything else has been ejected on
102
+ materializes, plus `repos` (because `ensure` clones them). Everything else has been ejected on
103
103
  exactly that test — `teams` (nothing resolved a
104
104
  team), `mounts` (a one-implementation adapter enum over an `.env` key), `module-registries` (zero
105
105
  readers), `workflows`/`workflow-runs`/`workflow-triggers`/`cursors` and `migrations`/`migration-runs`
@@ -7,12 +7,12 @@ One descriptor file: `modules/<module>/collections/<name>.collection.yaml`. The
7
7
 
8
8
  | goal | how |
9
9
  |---|---|
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`) |
12
- | templateless | `dt collections add --name <n>` — emits a minimal compilable schema |
13
- | add a field | `dt <collection> add-field --name urgent --type boolean --default-value false` |
14
- | change / drop a field | `dt <collection> update-field …` · `remove-field --name <f>` |
15
- | delete a collection | `dt collections rm <name>` |
10
+ | new collection from a template | `dt schema add-collection --name research-docs --template docs` |
11
+ | move one into a namespace | `dt schema rename-collection doctors health/doctors` (or `doctors --namespace health`) |
12
+ | templateless | `dt schema add-collection --name <n>` — emits a minimal compilable schema |
13
+ | add a field | `dt schema add-field <collection> --name urgent --type boolean --default-value false` |
14
+ | change / drop a field | `dt schema update-field <collection> …` · `schema remove-field <collection> --name <f>` |
15
+ | delete a collection | `dt schema rm-collection <name>` |
16
16
  | what templates exist | `.dreamteamer/collection-templates/` |
17
17
 
18
18
  `--type` is sugar over JSON Schema: `string`/`text`, `markdown`, `boolean`, `number`, `integer`,
@@ -21,7 +21,7 @@ or a bare collection name for a reference into it. `--required true` widens `req
21
21
 
22
22
  ⚠ **The meta verbs write the WORKSPACE module only.** To change a field on a collection another
23
23
  module owns, either edit that module's descriptor by hand or add an `extends:` overlay.
24
- **`dt collections rename <old> <new>`** moves the descriptor, the records, the record filenames and
24
+ **`dt schema rename-collection <old> <new>`** moves the descriptor, the records, the record filenames and
25
25
  every inbound reference in ONE commit — including `x-reference` targets in other descriptors and any
26
26
  ui-view pointing at it. `<old> --namespace <ns>` is sugar for moving it into a namespace under the same
27
27
  bare name. It refuses a compiled source, a module-owned collection, a taken name, and an undeclared
@@ -35,7 +35,7 @@ A collection name may carry a slash-delimited namespace, and it becomes real dir
35
35
 
36
36
  | declare in the workspace `package.json` | create it | lands in | referenced as |
37
37
  |---|---|---|---|
38
- | `"namespaces": ["health"]` | `dt collections add --namespace health --name doctors` | `data/health/doctors/` | `health/doctors/dana-levi` |
38
+ | `"namespaces": ["health"]` | `dt schema add-collection --namespace health --name doctors` | `data/health/doctors/` | `health/doctors/dana-levi` |
39
39
 
40
40
  - **The default namespace is the empty prefix.** `tasks` stays `data/tasks/` and `tasks/kickoff`, so
41
41
  common entities need no prefix and adopting namespaces migrates nothing. `default` is RESERVED —
@@ -93,7 +93,7 @@ templates: [collection-templates/provenance] # merged at compile, every time
93
93
  reference already inherits its TARGET collection's `title_template`; author it there instead, once,
94
94
  rather than on every field pointing at it.
95
95
  - **Do not enum a field after the fact.** Enumerating a vocabulary the records already violate makes
96
- `check` fail on every pre-existing value. `dt <collection> values <field>` derives the real
96
+ `check` fail on every pre-existing value. `dt values <collection> <field>` derives the real
97
97
  vocabulary from the data — a filter dropdown gets it for free without locking the set.
98
98
  - **`icon` / `group`** are the studio nav's material-symbol icon and folder; ungrouped collections
99
99
  list at the top. `list_fields` is the SEED a module ships, not a competing source of truth — a
@@ -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 --status todo`), then walk them one at a
16
+ (`npm run --silent dt -- list tasks --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
  ```
@@ -55,7 +55,7 @@ description: audio present, no transcript yet
55
55
  - **Pick the signal carefully.** "Is it transcribed?" is `transcription._nempty` (the provenance
56
56
  object), NOT `transcript._nempty` — a body can be filled by hand with no provenance, which is
57
57
  exactly the case worth flagging as not-yet-done.
58
- - Read the queue with `dt commands for <collection>[/<id>] [--ids a,b] [--json]`.
58
+ - Read the queue with `dt commands <collection>[/<id>] [--ids a,b] [--json]`.
59
59
 
60
60
  ## common mistakes
61
61
 
@@ -46,7 +46,7 @@ and silently reverts to a fallback ordering on the next load.
46
46
 
47
47
  ## the CLI can write these
48
48
 
49
- `dt ui-views add|set|rm` — `set` takes dotted keys (`options.sort=-date`) and derives the record id
49
+ `dt schema add-view|set-view|rm-view` — `set-view` takes dotted keys (`options.sort=-date`) and derives the record id
50
50
  with the descriptor's own template, so a view saved from the CLI and one saved from the UI land on
51
51
  the **same record**. This is the one system-stored kind with full CLI write support, because it goes
52
52
  through the same compile gate.
@@ -45,7 +45,7 @@ demand:
45
45
 
46
46
  `npm run --silent dt -- help` is the command surface — don't learn the generic verbs and flags from
47
47
  prose; prose drifts. it does **not** list the purpose-built verbs some collections have
48
- (`collections add`, `<collection> add-field`, `repos ensure`) — those live in the skill that owns
48
+ (`schema add-collection`, `schema add-field <collection>`, `ensure`) — those live in the skill that owns
49
49
  them, and a verb absent from `help` still works.
50
50
 
51
51
  what you need to know *about* the CLI: collection verbs validate hard (invalid writes, **including
@@ -85,10 +85,37 @@ and deliberately nothing else — including nothing about people. There is no `u
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
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
88
+ work, e.g. `npm run --silent dt -- list tasks --status todo`. ⚠ **there is no `users` collection and
89
89
  no `@me`** (both removed in 0.8.0); read the operator from `git config user.name` at the point you
90
90
  need one, and never filter on a person unless this workspace owns a collection of them.
91
91
 
92
+ ## machine-specific references
93
+
94
+ a path that exists on only one machine — a synced folder, an external disk — is written as a
95
+ **template**, never as an absolute path:
96
+
97
+ ```yaml
98
+ source_file: ${env:FILES_FOLDER}/2026/q3.pdf
99
+ ```
100
+
101
+ | variable | renders to |
102
+ |---|---|
103
+ | `${env:NAME}` | `NAME`'s value in the workspace's `.env` — and only if `NAME` is listed in `dreamteamer.vars` in `package.json` |
104
+ | `${workspaceFolder}` | the workspace root, absolute |
105
+ | `${userHome}` | the current user's home directory |
106
+
107
+ - **declare the key before using it**: `"dreamteamer": { "vars": ["FILES_FOLDER"] }`. an undeclared
108
+ key and a declared-but-absent one are deliberately different errors — the first is a typo, the
109
+ second is a machine nobody has set up. `npm run compile` warns per declared var with no value in
110
+ `.env`, naming keys only.
111
+ - **render with `dt resolve`, the only substitution point**: `dt resolve '${env:FILES_FOLDER}/x'`, or
112
+ `dt resolve <collection>/<id> <field>` to render what a record already holds (an array field prints
113
+ one item per line). an argument containing `${` is always a template, so a ref-shaped one is never
114
+ split as a reference.
115
+ - ⚠ **templates are ordinary data — write them literally; nothing substitutes until resolve is
116
+ called.** `dt get`, `list`, `check` and every harness read the template verbatim. an un-namespaced
117
+ `${VAR}` is inert, so prose may mention `${…}` freely.
118
+
92
119
  ## common mistakes
93
120
 
94
121
  | mistake | why it bites |
@@ -99,3 +126,4 @@ and deliberately nothing else — including nothing about people. There is no `u
99
126
  | bare refs (`ada`, `data/contacts/x.contact.md`) | refs are `<collection>/<id>`; anything else fails check |
100
127
  | assuming a write was committed | it was not, unless `auto-commit` is on — `dt status` says what is pending |
101
128
  | `git add -A` in a shared tree | steals another session's uncommitted work, invisibly |
129
+ | an absolute machine path in a record | it is wrong on every other machine — write `${env:NAME}` and declare the key |
@@ -19,8 +19,8 @@ purpose.
19
19
  ## the verbs
20
20
 
21
21
  `npm run --silent dt -- help` lists the generic record verbs and their flags. read them there.
22
- but **`help` is not the whole surface** — collections with a purpose-built verb (`collections add`,
23
- `<collection> add-field`, `repos ensure`) don't appear in it, and a verb missing from `help`
22
+ but **`help` is not the whole surface** — collections with a purpose-built verb (`schema add-collection`,
23
+ `schema add-field <collection>`, `ensure`) don't appear in it, and a verb missing from `help`
24
24
  is not a verb that doesn't exist. when a skill names a verb, use the verb.
25
25
 
26
26
  what the help text can't tell you either way:
@@ -30,7 +30,7 @@ what the help text can't tell you either way:
30
30
  got) or an id that misses `id.pattern`. a rejected write leaves no partial state.
31
31
  - **every write verb commits by itself**, with the right subject — never stack another commit
32
32
  on top.
33
- - `set <id> <field>=` with an empty value **removes** the field; array fields take a
33
+ - `set <collection>/<id> <field>=` with an empty value **removes** the field; array fields take a
34
34
  comma-separated value (`--attendees contacts/a,contacts/b`).
35
35
  - `--json` works on every verb — use it whenever you're going to parse the output.
36
36
  - `npm run check` validates the whole workspace after the fact: report-only, never rewrites.
@@ -45,10 +45,10 @@ to label one of its records) — both resolved by compile from the id unless aut
45
45
 
46
46
  ## writing a record by hand
47
47
 
48
- **default to `dt <collection> add`** — id, defaults, validation and commit in one line. hand-write
48
+ **default to `dt add <collection>`** — id, defaults, validation and commit in one line. hand-write
49
49
  only when the CLI can't express the value: a nested map, or a long structured body.
50
50
 
51
- when you do, don't reconstruct the shape from the schema — **`dt <collection> get <existing-id>
51
+ when you do, don't reconstruct the shape from the schema — **`dt get <collection>/<existing-id>
52
52
  --json` prints the exact shape a valid record has**: which fields, which ref forms, dates as
53
53
  strings. copy a sibling, change what differs, and:
54
54
 
@@ -81,8 +81,8 @@ A collection may be scoped under a namespace declared in the workspace `package.
81
81
  QUALIFIED name is the collection's name everywhere:
82
82
 
83
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
84
+ dt add health/doctors --name "Dana Levi" # → data/health/doctors/dana-levi.doctor.md
85
+ dt add health/visits --name Checkup --date 2026-03-04 --doctor health/doctors/dana-levi
86
86
  ```
87
87
 
88
88
  - a reference is still `<collection>/<id>` — `health/doctors/dana-levi` is the collection