outcrop 0.1.0 → 0.1.2

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/docs/AGENTS.md CHANGED
@@ -13,6 +13,7 @@ You are working in (or against) an outcrop workspace: a directory of plain markd
13
13
 
14
14
  - Frontmatter is flat `key: value` only: no nesting, no multiline values. Lists are inline (`depends_on: [ST-001, ST-002]`). Dates are `YYYY-MM-DD`.
15
15
  - Valid `status`: `backlog | ready | in-progress | in-review | done | blocked`. Valid `priority`: `P1 | P2 | P3`.
16
+ - `order` is a number a human set by dragging a card. Leave it alone. Omit it on new tasks; never invent one to push your own work up the board.
16
17
  - Task body sections in fixed order: `## Description`, `## Subtasks`, `## Acceptance criteria`, `## Test steps`, `## Notes`.
17
18
  - Subtasks are `- [ ]` / `- [x]` checkboxes under `## Subtasks`. Do not reorder them: the API addresses checkboxes by index.
18
19
  - IDs: tasks `ST-###`, epics `E##`. Filenames: `ST-###-slug.md`, `E##-slug.md`. Bare ID mentions anywhere in the workspace auto-link; `depends_on` and `epic` create graph edges.
package/docs/API.md CHANGED
@@ -68,13 +68,29 @@ Body: any of
68
68
  {
69
69
  "status": "in-review",
70
70
  "priority": "P2",
71
+ "epic": "E02",
72
+ "body": "## Subtasks\n\n- [ ] rewritten\n",
71
73
  "checkbox": { "index": 0, "checked": true },
72
74
  "rev": "1784910833019.7715"
73
75
  }
74
76
  ```
75
77
 
78
+ - `body` replaces everything after the frontmatter. The frontmatter block is left byte-for-byte alone, so a body edit can never change an id, status, or rank. Over 1,000,000 characters is a `413`, never a silent truncation.
79
+
80
+ Plus exactly one of these, to move the card within its column group (see [SPEC: Ordering](SPEC.md#ordering)):
81
+
82
+ ```json
83
+ { "move": "up" } // or "down": swap with the neighbour
84
+ { "before": "ST-004" } // place immediately above that task
85
+ { "after": "ST-004" } // place immediately below it
86
+ ```
87
+
76
88
  - `rev` (recommended, from a prior GET): request is rejected if the file changed since. Omitting `rev` skips the check: last write wins. Multi-agent setups must send it.
77
89
  - Mutations are format-preserving: only the targeted frontmatter line or checkbox is rewritten.
90
+ - A move is resolved against the destination, so `status` and `epic` in the same request are applied first: `{"status": "done", "before": "ST-004"}` moves the card to `done` and places it above ST-004 there.
91
+ - `epic` must name an epic that exists, or the request is a 400. `""` clears it.
92
+ - A move that would run past either end of the group is a no-op, not an error.
93
+ - **A move can write more than one file.** Placing a card usually rewrites only its own `order`, but the first move in a never-ordered group stamps ranks on its siblings, and a group that runs out of room between two ranks is respaced. `rev` guards the named task only — the sibling writes are not checked.
78
94
  - With `BOARD_GIT_COMMIT=1`, each successful PATCH becomes a git commit (`ST-001: ready -> in-progress via board`).
79
95
 
80
96
  Responses:
@@ -83,12 +99,22 @@ Responses:
83
99
  |---|---|---|
84
100
  | 200 | applied | `{ "ok": true, "rev": "<new rev>" }` |
85
101
  | 200 (no-op) | nothing changed | `{ "ok": true, "rev": "...", "unchanged": true }` |
86
- | 400 | invalid status/priority/checkbox/JSON | `{ "error": "..." }` |
102
+ | 400 | invalid status/priority/epic/checkbox/JSON, or a `before`/`after` target not in the group | `{ "error": "..." }` |
87
103
  | 404 | unknown id | `{ "error": "..." }` |
88
104
  | 409 | stale rev: file changed since read | `{ "error": "stale: ..." }` |
89
105
 
90
106
  On 409: re-GET the item, reconcile, retry with the new rev.
91
107
 
108
+ ### `GET /api/docs?file=REL.md`
109
+
110
+ The markdown source of a document, which is what `/docs` renders rather than serves:
111
+
112
+ ```json
113
+ { "file": "NOTES.md", "body": "# Notes\n\n…", "rev": "1784910833019.7715" }
114
+ ```
115
+
116
+ `body` excludes the frontmatter block, matching what `PATCH` writes back. `404` for an unknown or out-of-workspace file. This is what the in-page editor reads.
117
+
92
118
  ### `PATCH /api/docs?file=REL.md`
93
119
 
94
120
  Toggle a checkbox in a plain document, which has no id to address it by:
@@ -98,6 +124,15 @@ curl -X PATCH 'localhost:4311/api/docs?file=NOTES.md' -H 'content-type: applicat
98
124
  -d '{"checkbox":{"index":2,"checked":true},"rev":"<rev>"}'
99
125
  ```
100
126
 
127
+ Or replace the whole body:
128
+
129
+ ```bash
130
+ curl -X PATCH 'localhost:4311/api/docs?file=NOTES.md' -H 'content-type: application/json' \
131
+ -d '{"body":"# Notes\n\nRewritten.\n","rev":"<rev>"}'
132
+ ```
133
+
134
+ `body` replaces everything after the frontmatter, which is preserved exactly. Over 1,000,000 characters is a `413`. A body identical to what is on disk is a `200` with `unchanged: true` and no write, so an editor that autosaves on a timer costs nothing when nothing was typed.
135
+
101
136
  Checkboxes only — a document is not a task, so there is no status or priority to set. `index` counts `- [ ]` / `- [x]` lines from the top of the file, skipping fenced code blocks, exactly as it does for a task. `rev` is optional and behaves as it does elsewhere: supply it and a concurrent change is a `409`. `404` for an unknown or out-of-workspace file, `400` for an index that does not exist.
102
137
 
103
138
  ### `POST /api/tasks`, `POST /api/epics`, `POST /api/docs`
package/docs/SPEC.md CHANGED
@@ -38,12 +38,21 @@ epic: E01 # owning epic id
38
38
  status: ready # default set: backlog | ready | in-progress | in-review | done | blocked
39
39
  # a workspace can redefine this set via "columns" in .outcrop.json
40
40
  priority: P1 # P1 | P2 | P3
41
+ order: 150 # optional manual rank inside its column and epic; see below
41
42
  depends_on: [] # list of task ids
42
43
  created: 2026-07-07
43
44
  ```
44
45
 
45
46
  Missing keys default to: `status: backlog`, `priority: P3`, empty strings/lists.
46
47
 
48
+ #### Ordering
49
+
50
+ The board draws each column grouped by `epic`, and each group sorted by `order` ascending. A task with no `order` sorts after every task that has one, falling back to priority then id. A workspace where nobody has reordered anything therefore looks exactly as it did before this key existed, and writing `order` is never required.
51
+
52
+ `order` is any finite number, and the gaps are deliberate: the board writes ranks spaced by 100 so an insert between two cards is a midpoint and rewrites one file. When two neighbours are closer than `0.001` the whole group is respaced to `100, 200, 300, …` in one pass.
53
+
54
+ Ranks are scoped to one column of one epic. The same value may appear in another column or under another epic without meaning anything. Moving a task between columns or epics leaves its `order` valid only for where it landed, so the board rewrites it on arrival.
55
+
47
56
  ### Epic keys
48
57
 
49
58
  ```yaml
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "outcrop",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Serve a folder of markdown tasks and docs as a live kanban board, docs site, and agent API. AI-native, zero-config, files are the database.",
5
5
  "type": "module",
6
6
  "bin": {