dreamteamer 0.6.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/LICENSE +202 -0
- package/NOTICE +16 -0
- package/README.md +83 -0
- package/agents/dreamteamer.agent.md +7 -0
- package/bin/dreamteamer.js +65 -0
- package/collection-templates/docs.collection-template.yaml +14 -0
- package/collection-templates/entity.collection-template.yaml +16 -0
- package/collections/agents.collection.yaml +33 -0
- package/collections/collection-templates.collection.yaml +20 -0
- package/collections/collections.collection.yaml +78 -0
- package/collections/command-bindings.collection.yaml +46 -0
- package/collections/commands.collection.yaml +36 -0
- package/collections/repos.collection.yaml +42 -0
- package/collections/skills.collection.yaml +22 -0
- package/collections/ui-views.collection.yaml +48 -0
- package/collections/users.collection.yaml +21 -0
- package/package.json +58 -0
- package/skills/building-dreamteamer/SKILL.md +117 -0
- package/skills/building-dreamteamer/references/agents.md +44 -0
- package/skills/building-dreamteamer/references/before-you-build.md +42 -0
- package/skills/building-dreamteamer/references/collections.md +120 -0
- package/skills/building-dreamteamer/references/commands.md +69 -0
- package/skills/building-dreamteamer/references/skills.md +73 -0
- package/skills/building-dreamteamer/references/ui-components.md +78 -0
- package/skills/building-dreamteamer/references/ui-views.md +59 -0
- package/skills/using-dreamteamer/SKILL.md +100 -0
- package/skills/using-dreamteamer/references/git-events.md +64 -0
- package/skills/using-dreamteamer/references/records.md +102 -0
- package/src/check.js +193 -0
- package/src/cli.js +250 -0
- package/src/collections-cli.js +389 -0
- package/src/commit.js +117 -0
- package/src/compile.js +747 -0
- package/src/events.js +124 -0
- package/src/field-values.js +69 -0
- package/src/filter.js +107 -0
- package/src/harnesses.js +233 -0
- package/src/history.js +64 -0
- package/src/init.js +307 -0
- package/src/presentation.js +190 -0
- package/src/record-commands.js +84 -0
- package/src/records.js +73 -0
- package/src/runtime.js +96 -0
- package/src/schema-ops.js +263 -0
- package/src/semver.js +32 -0
- package/src/server.js +291 -0
- package/src/store.js +450 -0
- package/src/template.js +98 -0
- package/src/temporal.js +149 -0
- package/src/workspace.js +51 -0
- package/src/yaml.js +6 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# skills
|
|
2
|
+
|
|
3
|
+
A folder-shape record: `modules/<module>/skills/<name>/SKILL.md`. The folder name IS the id,
|
|
4
|
+
and extra files (references, scripts, assets) travel with the folder.
|
|
5
|
+
|
|
6
|
+
## create — and don't
|
|
7
|
+
|
|
8
|
+
**Create:** a technique that wasn't obvious, will recur, and applies beyond one record.
|
|
9
|
+
**Don't:** one-off fixes (just do them), workspace conventions (`CLAUDE.md`), or anything a
|
|
10
|
+
validator can enforce mechanically — automate that instead and save prose for judgment calls.
|
|
11
|
+
|
|
12
|
+
## the description is a TRIGGER, never a summary
|
|
13
|
+
|
|
14
|
+
The description is what a session scans to decide whether to load the skill. It must state **when to
|
|
15
|
+
use it** — symptoms, situations, verbs — and must NOT summarize the workflow: a description that
|
|
16
|
+
summarizes the process becomes a shortcut the agent follows *instead of reading the skill*, silently
|
|
17
|
+
skipping the steps the summary dropped.
|
|
18
|
+
|
|
19
|
+
```yaml
|
|
20
|
+
# ✖ workflow summary — the agent may follow this and never read the body
|
|
21
|
+
description: transcribes audio via whisper then fills the speaker map then commits
|
|
22
|
+
# ✔ trigger only
|
|
23
|
+
description: use when a meeting recording or pasted transcript needs to land in its meeting record
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Third person, lead with "use when", pack in searchable keywords (error strings, symptoms, synonyms,
|
|
27
|
+
tool names). Name = verb-first gerund (`writing-x`, `detecting-y`).
|
|
28
|
+
|
|
29
|
+
## body craft
|
|
30
|
+
|
|
31
|
+
- **Lean.** Aim under ~500 words in `SKILL.md`; concrete over complete — what to read first, the
|
|
32
|
+
exact shape to produce, the runnable commands. Cross-reference sibling skills instead of repeating
|
|
33
|
+
them.
|
|
34
|
+
- **Progressive disclosure for anything larger.** Keep `SKILL.md` as the digest — routing plus the
|
|
35
|
+
rules that apply everywhere — and put per-topic detail in `references/<topic>.md` that the digest
|
|
36
|
+
points at by name. A session then pays for the map, not the whole territory. `building-dreamteamer`
|
|
37
|
+
and `using-dreamteamer` are both built this way.
|
|
38
|
+
- **One excellent example** beats many mediocre ones; real, adapted from a live workspace.
|
|
39
|
+
- **Discipline skills** (rules under pressure) must close loopholes explicitly: name the workarounds
|
|
40
|
+
and forbid them, add a rationalization table ("excuse → reality") and a red-flags list. A rule
|
|
41
|
+
without its loopholes named will be rationalized around.
|
|
42
|
+
- Flowcharts only for genuinely non-obvious decisions; tables for reference.
|
|
43
|
+
- **Write down the traps.** The most valuable line in most of these skills is a measured failure
|
|
44
|
+
mode — a limit, a silent-success bug, a stale-config symptom — because it transfers perfectly and
|
|
45
|
+
cost someone a day to find. Include the measurement; drop the identities around it.
|
|
46
|
+
|
|
47
|
+
## no personal or account data
|
|
48
|
+
|
|
49
|
+
Skills ship with modules and are read by any operator — never bake in secrets, keys, names, emails
|
|
50
|
+
or account-specific paths. Per-install values go through `.env` (gitignored); the skill names the
|
|
51
|
+
variable it reads and what happens when it is missing.
|
|
52
|
+
|
|
53
|
+
## heavy assets
|
|
54
|
+
|
|
55
|
+
Models, caches and venvs live in dot-prefixed subfolders (`.models/`, `.cache/`, `.venv/`) with a
|
|
56
|
+
**skill-local `.gitignore`**. Compile skips dot-prefixed names, and local ignore rules travel with
|
|
57
|
+
the folder through extraction.
|
|
58
|
+
|
|
59
|
+
⚠ **Runnable assets must be referenced at their SOURCE path**, not under `.claude/skills/…` — that
|
|
60
|
+
is generated output, wiped and rebuilt every compile, and anything with local dependencies
|
|
61
|
+
(a `package.json`, a venv) only works where it was installed. Note the cost: a source path embeds
|
|
62
|
+
the module name, so renaming a module means updating every skill that names its own scripts.
|
|
63
|
+
|
|
64
|
+
## verify before calling it done
|
|
65
|
+
|
|
66
|
+
Compile, check, and — for any skill whose misreading would cost real work — **dispatch a
|
|
67
|
+
fresh-context subagent with a realistic task** and watch whether it finds, loads and follows the
|
|
68
|
+
skill correctly. What it gets wrong is what the skill still fails to say; fix and re-run. Reading
|
|
69
|
+
your own skill proves nothing.
|
|
70
|
+
|
|
71
|
+
**The reference bar:** the superpowers plugin skillset. Study a few of its skills before writing
|
|
72
|
+
one — its structure (overview / when-to-use with symptoms / quick reference / common mistakes), its
|
|
73
|
+
discipline patterns and its lean prose are the standard dreamteamer skills are held to.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# ui components
|
|
2
|
+
|
|
3
|
+
**Components are prebuilt code, not records.** There is no ui-components collection, no descriptor,
|
|
4
|
+
no compile step for the component itself. This is an ordinary Vue coding session against a module's
|
|
5
|
+
`studio/` source tree — *code registers everything renderable; yaml records configure and assemble.*
|
|
6
|
+
|
|
7
|
+
⚠ **Reach for a record first.** A `ui-view` pointing an existing `layout`/`edit`/`view` id at your
|
|
8
|
+
data costs no build and no code to maintain. Write a component only when nothing registered can do
|
|
9
|
+
the job.
|
|
10
|
+
|
|
11
|
+
## the registries
|
|
12
|
+
|
|
13
|
+
| registry | what it holds | bound by |
|
|
14
|
+
|---|---|---|
|
|
15
|
+
| `edits` | field editors + whole-record Edit pages | a field's `edit` meta; `scope: 'record'` for a page |
|
|
16
|
+
| `views` | field read-renderers + whole-record View pages | a field's `view` meta |
|
|
17
|
+
| `lists` | collection browse arrangements (table, cards, kanban, …) | a `ui-view` record's `layout` |
|
|
18
|
+
| `apps`, `panels`, `operations` | routed subtrees, dashboard panels, flow operations | registration alone |
|
|
19
|
+
|
|
20
|
+
The host's own built-ins register through the exact same door a module uses — read its
|
|
21
|
+
`register-defaults.ts` as the reference.
|
|
22
|
+
|
|
23
|
+
## the module contract
|
|
24
|
+
|
|
25
|
+
A module ships a browser entry (`studio/app.js`, or a built `studio/dist/app.js`) that compile stages
|
|
26
|
+
to `.dreamteamer/ui/<module>/app.js`; its **default export** is a register function:
|
|
27
|
+
|
|
28
|
+
```js
|
|
29
|
+
export default ({ registerEdit, registerView, registerList, registerApp, registerPanel }) => {
|
|
30
|
+
registerList({ id: 'kanban', name: 'Kanban', component: MyKanban, fillsHeight: true });
|
|
31
|
+
};
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
- **Never bundle Vue.** The host exposes its own Vue as `window.Vue` *before* importing any module
|
|
35
|
+
entry; two copies break reactivity silently. Use `window.Vue`, or mark `vue` external and map it to
|
|
36
|
+
the global.
|
|
37
|
+
- **Give every entry an explicit stable `id`.** That string is what a `ui-view.layout` or a field's
|
|
38
|
+
`edit`/`view` meta names. Changing it breaks every binding.
|
|
39
|
+
- **`types: []` opts an Edit/View out of kind-inference.** A non-empty `types` array makes it a *kind
|
|
40
|
+
default* for that wire type — which means a bare `string` or `json` field anywhere in the workspace
|
|
41
|
+
silently gets your bespoke widget. Most custom components should stay `types: []`.
|
|
42
|
+
- **`fillsHeight: true`** declares that this List owns its own scrolling; the page then stops
|
|
43
|
+
scrolling vertically and hands the List the leftover height. Layouts that should grow the page
|
|
44
|
+
(table, cards) must not set it.
|
|
45
|
+
- **Failures are isolated, not surfaced.** A module whose entry fails to import or throws while
|
|
46
|
+
registering is caught, warned and skipped — the surface still loads, your component just never
|
|
47
|
+
appears. **Read the browser console**; nothing else will tell you.
|
|
48
|
+
|
|
49
|
+
⚠ **A module registering a CORE id WINS, silently.** Module bundles load after the built-ins and the
|
|
50
|
+
registry is a `Map.set`, so a module `kanban` shadows the core `kanban` with no warning anywhere —
|
|
51
|
+
which once meant an operator had been using a strictly worse board for weeks and nothing could reveal
|
|
52
|
+
it from the outside. Never reuse a core id unless shadowing is exactly what you mean.
|
|
53
|
+
|
|
54
|
+
⚠ **Portalled UI cannot rely on scoped CSS.** Menus, popovers and dialogs are teleported outside the
|
|
55
|
+
component subtree, so a scoped rule looks correct in the source and is simply absent at runtime — the
|
|
56
|
+
failure mode is invisible chrome, not an error. Define those styles globally.
|
|
57
|
+
|
|
58
|
+
## workflow
|
|
59
|
+
|
|
60
|
+
1. Write the component in the module's `studio/` tree.
|
|
61
|
+
2. Register it in that module's `app.js` with a stable `id`.
|
|
62
|
+
3. Plain-JS `app.js` needs no build; a module wanting a toolchain builds to `studio/dist/app.js`
|
|
63
|
+
itself. Declare any Lists in `package.json` `dreamteamer.studio.layouts`, then compile to stage it.
|
|
64
|
+
4. Look at it in the real surface.
|
|
65
|
+
5. **Bind it** — a field's `edit`/`view` meta, or a `ui-view.layout` naming the `id`. Only this step
|
|
66
|
+
touches records.
|
|
67
|
+
|
|
68
|
+
## common mistakes
|
|
69
|
+
|
|
70
|
+
| mistake | reality |
|
|
71
|
+
|---|---|
|
|
72
|
+
| looking for a ui-components collection | there isn't one; this is code |
|
|
73
|
+
| bundling Vue | two copies; reactivity dies silently |
|
|
74
|
+
| assuming a registration error is reported | swallowed by fault isolation — read the console |
|
|
75
|
+
| `types: ['string']` on a bespoke widget | it becomes the default for every plain string field |
|
|
76
|
+
| omitting `id`, or renaming it later | the id is the binding surface |
|
|
77
|
+
| binding before building | the id does not exist yet; the view renders nothing |
|
|
78
|
+
| reusing a core layout id | silently shadows the built-in with no warning |
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# ui-views
|
|
2
|
+
|
|
3
|
+
`modules/<module>/ui-views/<name>.ui-view.yaml`. **A ui-view is a binding, not code** — a
|
|
4
|
+
route plus the id of an already-registered layout, plus how to shape the data. Nothing to build.
|
|
5
|
+
|
|
6
|
+
The surface reads compiled ui-view records at boot: `nav` becomes a sidebar entry, `path` becomes a
|
|
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.
|
|
9
|
+
|
|
10
|
+
```yaml
|
|
11
|
+
path: /inbox
|
|
12
|
+
nav: { label: Inbox, icon: inbox, order: 1 }
|
|
13
|
+
target: list
|
|
14
|
+
collection: collections/tasks
|
|
15
|
+
layout: table
|
|
16
|
+
filter: { assignee: { _eq: "@me" } } # operator objects, never a bare value
|
|
17
|
+
options: { columns: [name, status, due, run], sort: -due }
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
| field | required | notes |
|
|
21
|
+
|---|---|---|
|
|
22
|
+
| `path` | yes | the route — `/inbox`, `/views/meetings/recent` |
|
|
23
|
+
| `target` | yes | `list`, `item`, or `page` (freestanding) |
|
|
24
|
+
| `layout` | yes | the id of a **registered** layout (`table`, `cards`, `kanban`, `calendar`, `map`, + module-declared) |
|
|
25
|
+
| `collection` | for `list`/`item` | qualified: `collections/<name>` |
|
|
26
|
+
| `nav` | no | `label`/`icon`/`order`; omit for direct-link-only views |
|
|
27
|
+
| `default` | no | `true` makes this the collection's DEFAULT view at `/content/<collection>` |
|
|
28
|
+
|
|
29
|
+
## default views vs named views
|
|
30
|
+
|
|
31
|
+
A collection's default presentation **is an ordinary ui-view record** — `default: true`, path
|
|
32
|
+
`/content/<collection>`. A named view is the same record with its own path plus a `nav.label`. One
|
|
33
|
+
shape, one home, both agent-writable and both diffable in git.
|
|
34
|
+
|
|
35
|
+
⚠ **A view's `options.columns` REPLACES the descriptor's `list_fields`; it does not merge.** And a
|
|
36
|
+
column naming a field the schema lacks is **dropped, not fallen back from** — which is how a core
|
|
37
|
+
inbox view asking for `title` on a collection whose field is `name` rendered every row nameless with
|
|
38
|
+
no error. Check the descriptor's real field names against every column you write.
|
|
39
|
+
|
|
40
|
+
⚠ **`options.sort` must be written even when empty** (`sort: ''`), or "unsorted" cannot round-trip
|
|
41
|
+
and silently reverts to a fallback ordering on the next load.
|
|
42
|
+
|
|
43
|
+
## the CLI can write these
|
|
44
|
+
|
|
45
|
+
`dt ui-views add|set|rm` — `set` takes dotted keys (`options.sort=-date`) and derives the record id
|
|
46
|
+
with the descriptor's own template, so a view saved from the CLI and one saved from the UI land on
|
|
47
|
+
the **same record**. This is the one system-stored kind with full CLI write support, because it goes
|
|
48
|
+
through the same compile gate.
|
|
49
|
+
|
|
50
|
+
## common mistakes
|
|
51
|
+
|
|
52
|
+
| mistake | reality |
|
|
53
|
+
|---|---|
|
|
54
|
+
| a `layout` id you assumed exists | compile validates it only for `target: list`; otherwise the view renders nothing |
|
|
55
|
+
| bare `collection: tasks` | qualified refs only |
|
|
56
|
+
| `filter: { assignee: "@me" }` | filters are operator objects: `{ assignee: { _eq: "@me" } }` |
|
|
57
|
+
| a column the schema does not have | dropped silently — the row loses that value with no error |
|
|
58
|
+
| 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 |
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: using-dreamteamer
|
|
3
|
+
description: always load first — describes this dreamteamer workspace, its collections, conventions and your pending tasks
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# using dreamteamer
|
|
7
|
+
|
|
8
|
+
this is a **dreamteamer** workspace: collections, skills, agents and commands are records compiled
|
|
9
|
+
from sources into a runtime the harness reads.
|
|
10
|
+
|
|
11
|
+
**core principle:** read the compiled runtime, write the sources, compile — then `dt commit` to publish.
|
|
12
|
+
|
|
13
|
+
## when to use
|
|
14
|
+
|
|
15
|
+
load this **first, every session** in this repo. reload mid-session on any of these symptoms: you're
|
|
16
|
+
about to guess a collection's fields; you can't tell whether the file to edit lives under
|
|
17
|
+
`modules/*/<kind>/` or `.dreamteamer/`; you wrote something and the harness didn't notice; you're
|
|
18
|
+
unsure which skill owns the job in front of you.
|
|
19
|
+
|
|
20
|
+
**this file is the MAP, not the procedure.** Detail lives in two references beside it, loaded on
|
|
21
|
+
demand:
|
|
22
|
+
|
|
23
|
+
| load | when |
|
|
24
|
+
|---|---|
|
|
25
|
+
| `references/records.md` | reading, creating, updating, renaming or deleting any record — the CLI verbs, hand-writing rules, the hard rules about ids and renames |
|
|
26
|
+
| `references/git-events.md` | "what changed while I was away" — `dt changes`, and how record events are derived from git history |
|
|
27
|
+
|
|
28
|
+
## the contract
|
|
29
|
+
|
|
30
|
+
| concern | where | rule |
|
|
31
|
+
|---|---|---|
|
|
32
|
+
| schemas (read) | `.dreamteamer/collections/*.collection.yaml` | the single source of truth for what exists and its shape. **never edit under `.dreamteamer/`** — generated and gitignored |
|
|
33
|
+
| provenance | `.dreamteamer/manifest.yaml` | which module shipped which entry |
|
|
34
|
+
| sources (write) | `modules/<module>/` — **including the workspace's own**, the `dreamteamer.workspace-module` named in `package.json` | a source folder at the workspace ROOT is a compile ERROR. same-name collisions across modules are compile errors too. after ANY source change: `npm run compile` |
|
|
35
|
+
| content records | `data/<collection>/` | per each descriptor's `storage.path` |
|
|
36
|
+
| operational records | `state/<collection>/` | whatever a module declares there; core ships none |
|
|
37
|
+
|
|
38
|
+
- a record is a `<id>.<suffix>.<ext>` file (or a folder, for folder-shape collections). **the id is
|
|
39
|
+
the path** inside the collection folder minus suffix and extension — nested folders join in:
|
|
40
|
+
`data/meetings/2026/07/standup.meeting.md` ⇒ id `2026/07/standup`.
|
|
41
|
+
- **references are `<collection>/<id>`** strings — always qualified, greppable, never a bare name and
|
|
42
|
+
never a file path.
|
|
43
|
+
|
|
44
|
+
## the CLI is the front door
|
|
45
|
+
|
|
46
|
+
`npm run --silent dt -- help` is the command surface — don't learn the generic verbs and flags from
|
|
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
|
|
49
|
+
them, and a verb absent from `help` still works.
|
|
50
|
+
|
|
51
|
+
what you need to know *about* the CLI: collection verbs validate hard (invalid writes, **including
|
|
52
|
+
unknown fields**, are rejected before disk) **and commit for you** with the right subject. `npm run
|
|
53
|
+
compile` after every source change, `npm run check` after bulk edits, `npm run --silent dt -- status`
|
|
54
|
+
when you're not sure the runtime is fresh.
|
|
55
|
+
|
|
56
|
+
## routing
|
|
57
|
+
|
|
58
|
+
| the request is about | load |
|
|
59
|
+
|---|---|
|
|
60
|
+
| a record — read, create, update, rename, delete | `references/records.md` |
|
|
61
|
+
| authoring anything under a module's source folders — a collection, field, skill, command, agent, ui-view, or component code | `building-dreamteamer` |
|
|
62
|
+
| "what changed while I was away" | `references/git-events.md` |
|
|
63
|
+
| the workspace lacks the capability entirely | `building-dreamteamer` → `references/before-you-build.md` |
|
|
64
|
+
|
|
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.
|
|
68
|
+
|
|
69
|
+
## conventions
|
|
70
|
+
|
|
71
|
+
- **a write puts a record on disk; `dreamteamer commit` publishes it.** committing is POLICY —
|
|
72
|
+
`"auto-commit"` in the workspace's `package.json`, default off — not a property of the write. so
|
|
73
|
+
commit when a logical change is complete, and run `dt status` if you are unsure what is pending.
|
|
74
|
+
subjects still read `dreamteamer: <verb> <detail>` for a single record (`dt commit` composes them
|
|
75
|
+
from git's own status letters), and a multi-record commit says what it swept.
|
|
76
|
+
- **one commit per REPO.** a module can own its records (`owns-data` in its package.json), and git
|
|
77
|
+
has no cross-repo commit — so a rename whose inbound refs live in another repo is TWO commits.
|
|
78
|
+
`dt commit` prints both. `dt commit <collection> …` scopes it; `--dry-run` shows the set first.
|
|
79
|
+
- **never `git add -A`, `git add .`, or `git commit -a`.** stage explicit paths. more than one agent
|
|
80
|
+
can be working in a tree, and a blanket add silently commits whatever another session has
|
|
81
|
+
uncommitted right now — under your subject, leaving `git status` clean and the damage invisible.
|
|
82
|
+
the CLI's own writes are pathspec-scoped for exactly this reason, which is why it is the preferred
|
|
83
|
+
path for record writes.
|
|
84
|
+
- **validate after bulk edits**: `npm run check` reports violations and never modifies files.
|
|
85
|
+
- workspace-level rules live in `CLAUDE.md`, and a workspace's decision log (where one exists) wins
|
|
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**.
|
|
90
|
+
|
|
91
|
+
## common mistakes
|
|
92
|
+
|
|
93
|
+
| mistake | why it bites |
|
|
94
|
+
|---|---|
|
|
95
|
+
| editing something under `.dreamteamer/` | generated + gitignored; the change vanishes on the next compile |
|
|
96
|
+
| changing a source and not compiling | the harness and `check` still read the stale runtime |
|
|
97
|
+
| 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
|
+
| assuming a write was committed | it was not, unless `auto-commit` is on — `dt status` says what is pending |
|
|
100
|
+
| `git add -A` in a shared tree | steals another session's uncommitted work, invisibly |
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# detecting data changes via git
|
|
2
|
+
|
|
3
|
+
**Core principle:** record events are never observed live — they are **derived from git history**. A
|
|
4
|
+
closed laptop loses nothing, and every derivation is auditable and replayable forever. History IS the
|
|
5
|
+
queue; there is no events file, and there never should be.
|
|
6
|
+
|
|
7
|
+
## the verb
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
dt changes # since the last commit
|
|
11
|
+
dt changes --since <sha> # since any commit
|
|
12
|
+
dt changes --json # for a program
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Per record it reports the collection, the id and one of `item-added` / `item-updated` /
|
|
16
|
+
`item-removed`, grouped by collection with counts. **Read-only by construction** — there is no cursor
|
|
17
|
+
to advance and nothing is stored, so running it twice is free and running it wrong costs nothing.
|
|
18
|
+
|
|
19
|
+
## when to use
|
|
20
|
+
|
|
21
|
+
The operator asks what changed or what they missed; you are reconciling after a batch of edits or a
|
|
22
|
+
bulk rewrite; you want to know what a range of commits actually did to the data.
|
|
23
|
+
|
|
24
|
+
**Not for:** ordinary "show me the diff" questions — plain `git log` / `git diff` is better. Not for
|
|
25
|
+
reading or writing individual records (`references/records.md`).
|
|
26
|
+
|
|
27
|
+
## the mechanism
|
|
28
|
+
|
|
29
|
+
1. **Diff** — `git diff --name-status <sha>..HEAD -- data/ state/`.
|
|
30
|
+
2. **Map** — each path maps to a collection via the compiled descriptors' `storage.path`
|
|
31
|
+
(longest-prefix match; the suffix + codec must also match a record file, and folder-shape
|
|
32
|
+
collections match on their `entry`). The id is the path inside the collection folder minus
|
|
33
|
+
`.<suffix>.<ext>`. **A changed path that matches no descriptor is not a record** and is skipped —
|
|
34
|
+
source and runtime churn are not data events.
|
|
35
|
+
3. **Classify** — the git status letter becomes the event: `A` → added, `M` → updated, `D` → removed.
|
|
36
|
+
**A rename emits removed + added**; there is deliberately no `item-renamed` event, because the id IS
|
|
37
|
+
the path and a moved record is a different record as far as any consumer is concerned.
|
|
38
|
+
|
|
39
|
+
## what this used to be, and why the rest went
|
|
40
|
+
|
|
41
|
+
Until 2026-07-31 this mechanism was the front half of `dt sync`, which also matched
|
|
42
|
+
`workflow-triggers` records, **created `workflow-runs`**, and advanced a per-evaluator cursor. That
|
|
43
|
+
whole layer was removed: measured over three days it had produced 1 workflow record and 9 runs all from
|
|
44
|
+
a single burst, **7 of them abandoned mid-flight**, against a cursor that had not advanced — while the
|
|
45
|
+
work it was meant to automate was being done by a chain of commands a person runs.
|
|
46
|
+
|
|
47
|
+
The derivation survived because it is the half that was actually used, for catch-up. Worth keeping from
|
|
48
|
+
that design if automation is ever rebuilt:
|
|
49
|
+
|
|
50
|
+
- **Never store an event queue.** A queue drifts from reality; history cannot.
|
|
51
|
+
- **Any evaluator must be idempotent over a range** — re-running must not act twice. The old design
|
|
52
|
+
keyed that on `trigger + item + commit`, which is the shape to reuse.
|
|
53
|
+
- **A migration is not a data event.** A bulk rewrite looks like N added records to git, so anything
|
|
54
|
+
acting on events must be scoped past it rather than run over it.
|
|
55
|
+
|
|
56
|
+
## common mistakes
|
|
57
|
+
|
|
58
|
+
| mistake | reality |
|
|
59
|
+
|---|---|
|
|
60
|
+
| hand-rolling the diff + path mapping | `dt changes` is the mechanism; a hand-roll misses folder-shape records and the rename split |
|
|
61
|
+
| treating any changed path as a record | only paths matching a descriptor's `storage.path` + suffix + codec are records |
|
|
62
|
+
| diffing the whole tree | scope to `data/` + `state/`; source and runtime churn are not item events |
|
|
63
|
+
| writing an events file to "remember" what changed | history is the record; anything you write can drift from it |
|
|
64
|
+
| reading `dt changes` output as a to-do list | it says what changed, not what it means — the judgement is yours |
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# working with structured data files
|
|
2
|
+
|
|
3
|
+
**core principle:** the CLI is the default path — it validates before disk, generates the id,
|
|
4
|
+
materializes defaults and commits with the right subject. direct file edits stay first-class,
|
|
5
|
+
but then *you* owe every rule below.
|
|
6
|
+
|
|
7
|
+
## when to use
|
|
8
|
+
|
|
9
|
+
any time a record is read, created, changed, renamed or removed — a task, a contact, a meeting,
|
|
10
|
+
a doc, anything under `data/` or `state/`. load it especially when you catch yourself about to
|
|
11
|
+
`mv` a record file, hand-write frontmatter from memory, or set a field you haven't read in the
|
|
12
|
+
descriptor.
|
|
13
|
+
|
|
14
|
+
**not for:** schema changes (`building-dreamteamer` → `references/collections.md`), or system-stored records — skills, agents,
|
|
15
|
+
commands, ui-views, collections. those are *sources*: edit the file under the owning
|
|
16
|
+
module (`modules/<module>/<kind>/`) and run `npm run compile`; the CLI refuses them on
|
|
17
|
+
purpose.
|
|
18
|
+
|
|
19
|
+
## the verbs
|
|
20
|
+
|
|
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`
|
|
24
|
+
is not a verb that doesn't exist. when a skill names a verb, use the verb.
|
|
25
|
+
|
|
26
|
+
what the help text can't tell you either way:
|
|
27
|
+
|
|
28
|
+
- **validation is hard and it includes unknown fields.** a typo'd key (`--assinee`) is rejected
|
|
29
|
+
with nothing written, same as a dangling ref, a bad enum value (the error echoes the value it
|
|
30
|
+
got) or an id that misses `id.pattern`. a rejected write leaves no partial state.
|
|
31
|
+
- **every write verb commits by itself**, with the right subject — never stack another commit
|
|
32
|
+
on top.
|
|
33
|
+
- `set <id> <field>=` with an empty value **removes** the field; array fields take a
|
|
34
|
+
comma-separated value (`--attendees contacts/a,contacts/b`).
|
|
35
|
+
- `--json` works on every verb — use it whenever you're going to parse the output.
|
|
36
|
+
- `npm run check` validates the whole workspace after the fact: report-only, never rewrites.
|
|
37
|
+
|
|
38
|
+
## before writing anything
|
|
39
|
+
|
|
40
|
+
read the compiled descriptor: `.dreamteamer/collections/<collection>.collection.yaml`.
|
|
41
|
+
it defines `storage` (path/codec/shape/suffix), `id` (`generate` template + `pattern`), and
|
|
42
|
+
`schema` (JSON Schema; the `x-` keywords carry the domain semantics — `x-reference`, `x-body`,
|
|
43
|
+
`x-title-template`). It also carries `title` (what to CALL the collection) and `title_template` (how
|
|
44
|
+
to label one of its records) — both resolved by compile from the id unless authored.
|
|
45
|
+
|
|
46
|
+
## writing a record by hand
|
|
47
|
+
|
|
48
|
+
**default to `dt <collection> add`** — id, defaults, validation and commit in one line. hand-write
|
|
49
|
+
only when the CLI can't express the value: a nested map, or a long structured body.
|
|
50
|
+
|
|
51
|
+
when you do, don't reconstruct the shape from the schema — **`dt <collection> get <existing-id>
|
|
52
|
+
--json` prints the exact shape a valid record has**: which fields, which ref forms, dates as
|
|
53
|
+
strings. copy a sibling, change what differs, and:
|
|
54
|
+
|
|
55
|
+
- put the file where the id says: the id IS its path inside `storage.path`, minus suffix and
|
|
56
|
+
extension (folder-shape records are a folder named `<id>` holding the descriptor's `entry`).
|
|
57
|
+
ids are built from **creation-time** values only, never a mutable field, and must satisfy
|
|
58
|
+
`id.pattern`.
|
|
59
|
+
- **materialize defaults explicitly** — write `status: todo` even though it's the schema default;
|
|
60
|
+
a file should be legible without its schema.
|
|
61
|
+
- `npm run check` is the only validation a hand-write gets. run it before you commit, once:
|
|
62
|
+
`dreamteamer: <collection> add <id>` (or `set <id>`, for an update).
|
|
63
|
+
|
|
64
|
+
example — `data/tasks/2026-07-25--fix-login-flow.task.md` (`md` codec: frontmatter holds the
|
|
65
|
+
fields, the body is the single `x-body: true` field):
|
|
66
|
+
|
|
67
|
+
```markdown
|
|
68
|
+
---
|
|
69
|
+
title: Fix login flow
|
|
70
|
+
status: todo
|
|
71
|
+
assignee: users/ada
|
|
72
|
+
due: '2026-07-28'
|
|
73
|
+
---
|
|
74
|
+
Users report the login button does nothing on mobile.
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## the hard rules
|
|
78
|
+
|
|
79
|
+
**never hand-rename or `mv` a record file** — the id IS the path, so a rename silently dangles
|
|
80
|
+
every inbound reference; `rename` moves the file and rewrites all refs in one commit. **never
|
|
81
|
+
delete a referenced record** (`rm` refuses for a reason — retarget first). **a changed title
|
|
82
|
+
never changes the id.** **one mutation, one commit.**
|
|
83
|
+
|
|
84
|
+
## common mistakes
|
|
85
|
+
|
|
86
|
+
| mistake | reality |
|
|
87
|
+
|---|---|
|
|
88
|
+
| `mv data/tasks/old.task.md …/new.task.md` | every inbound ref now dangles. use `dt … rename`. |
|
|
89
|
+
| renaming a file because the title changed | the id is not a display name — edit the field. |
|
|
90
|
+
| reaching for `--force` to get past the refuse | it leaves the inbound refs dangling. retarget them first — unless `rm` named a *prose* mention (a skill's example, a doc), which isn't a real reference and `check` won't flag. |
|
|
91
|
+
| hand-writing a record "because it's quicker" | no validation, no defaults, no id check, no commit. `dt … add` is one line. |
|
|
92
|
+
| omitting schema defaults from a hand-written file | the file stops being legible without the schema. |
|
|
93
|
+
| unquoted `due: 2026-07-28` | dreamteamer parses with CORE_SCHEMA so it stays a string *here*, but any default-schema YAML reader turns it into a timestamp. quote dates when hand-writing. |
|
|
94
|
+
| CLI-editing a skill / agent / command / collection | system sources — edit the module file, then `npm run compile`. |
|
|
95
|
+
| committing again after a CLI verb | the verb already committed; you'd sweep unrelated work into it. |
|
|
96
|
+
|
|
97
|
+
## red flags — stop
|
|
98
|
+
|
|
99
|
+
- you're about to `mv`, `cp` or `rm` a file under `data/` or `state/` directly
|
|
100
|
+
- you're writing a reference you haven't confirmed resolves
|
|
101
|
+
- you're editing anything under `.dreamteamer/` (generated, gitignored)
|
|
102
|
+
- you finished a bulk edit and haven't run `npm run check`
|