@chalksurf/cli 0.3.6 → 0.4.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 +24 -18
- package/dist/bin/chalksurf.js +10410 -9280
- package/docs/agents.md +63 -50
- package/docs/content-operations.md +36 -0
- package/docs/examples/authoritative-sheet-import-manifest.json +48 -0
- package/docs/examples/exercise-import-manifest.json +16 -9
- package/docs/examples/exercise-sheet-solution-import-manifest.json +13 -8
- package/docs/examples/exercise-sheet-translation-import-manifest.json +20 -0
- package/docs/examples/exercise-solution-import-manifest.json +13 -8
- package/docs/examples/sheet-import-manifest.json +12 -5
- package/docs/exit-codes.md +14 -4
- package/docs/manifest.md +12 -165
- package/docs/manual.md +44 -28
- package/docs/mcp.md +62 -57
- package/docs/migration-0.4.md +79 -0
- package/package.json +6 -3
- package/schemas/content-manifest.schema.json +2308 -0
- package/schemas/content-plan.schema.json +5003 -0
- package/schemas/exercise-import-manifest.schema.json +131 -101
- package/schemas/exercise-sheet-solution-import-manifest.schema.json +118 -90
- package/schemas/exercise-sheet-translation-import-manifest.schema.json +156 -0
- package/schemas/exercise-solution-import-manifest.schema.json +118 -90
- package/schemas/sheet-import-manifest.schema.json +547 -181
package/docs/manifest.md
CHANGED
|
@@ -1,174 +1,21 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Content manifests
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Use `--manifest FILE` for repeated content operations. Files and stdin (`--manifest -`) are limited to 16 MiB. A manifest is a strict object containing `schemaVersion: "v1"`, a canonical dot-separated `operation`, and `items`. Every item has a unique `itemId`; explicit target IDs must also be unique. Do not put profile, organization, wait, timeout, request ID, or artifact settings in the manifest. Competing flags or positional targets are rejected.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Local paths resolve relative to the manifest file. Stdin paths resolve relative to the current directory. Sources use `kind: "local"` with `path`, `kind: "directory"` with `path`, or `kind: "url"` with an HTTP(S) `url`. Optional `sourceId` identifies a source within its ordered group; `relativePath` sets a file's logical path, and `relativeRoot` applies to directory sources. File order matters. Duplicate source IDs within a group are rejected.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- `chalksurf exercise import --manifest <path|->`
|
|
9
|
-
- `chalksurf exercise import-solution --manifest <path|->`
|
|
10
|
-
- `chalksurf sheet import-solutions --manifest <path|->`
|
|
7
|
+
Exercise imports use optional `exerciseSheetId`, `sources`, and optional `targetLanguages`. Exercise solution imports require `exerciseId`; sheet solution imports require `exerciseSheetId`. Authoritative sheet translation imports require `exerciseSheetId`, `sourceLanguage`, `targetLanguage`, and `sources`. Target languages are the existing English enum names, such as `english` and `hungarian`.
|
|
11
8
|
|
|
12
|
-
|
|
9
|
+
A `sheet.import` item describes one logical group using exactly one of:
|
|
13
10
|
|
|
14
|
-
|
|
11
|
+
- `sources`, optional `targetFolderPath`, `title`, and `targetLanguages`.
|
|
12
|
+
- `sources` and `components`, each with a unique `componentId`, a `description` identifying the section, and optional destination/title/target languages.
|
|
13
|
+
- `base: {language, sources}` and `translations: [{language, sources}]`, with optional destination/title. Authoritative groups require explicit files or URLs, preserve language-local order, and accept no source roles.
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
The CLI accepts at most 20 logical sheet import groups and 100 known work units after component/language expansion. It never truncates inputs or implicitly splits an oversized atomic operation. Directory extraction and AI exercise counts remain unknown in preflight; no remote source is downloaded by `--dry-run`.
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
| --- | --- | --- | --- |
|
|
20
|
-
| `organizationId` | string | no | Overrides the default organization for this invocation. |
|
|
21
|
-
| `wait` | boolean | no | Behaves like `--wait`. The CLI also accepts `--wait`, which wins if set. Requested translations run as follow-up jobs listed in the import result. |
|
|
17
|
+
Examples in [examples](examples/) use this v1 contract. Old top-level `sheets`/`sources`, manifest organization/wait controls, and `translateTo` fields are rejected. Use `targetLanguages` in manifests and repeatable `--target-language` in direct commands.
|
|
22
18
|
|
|
23
|
-
|
|
19
|
+
Import results have `items` and `summary`; each item retains its identity and accepted jobs. Follow-up details and extracted resources appear in `observation.jobs` when waiting. Request/attempt evidence supports an intentional exact resend. Read [content operations](content-operations.md) before recovering an uncertain acceptance; never blindly reimport successful siblings.
|
|
24
20
|
|
|
25
|
-
|
|
26
|
-
| --- | --- | --- | --- |
|
|
27
|
-
| `sourceId` | string | no | Optional stable identifier for correlating source inputs to results. Must be unique within the manifest. |
|
|
28
|
-
| `kind` | `local` \| `directory` \| `url` | yes | Selects the source shape. |
|
|
29
|
-
|
|
30
|
-
### Source Kinds
|
|
31
|
-
|
|
32
|
-
`local`
|
|
33
|
-
|
|
34
|
-
| Field | Type | Required | Notes |
|
|
35
|
-
| --- | --- | --- | --- |
|
|
36
|
-
| `path` | string | yes | Local file path relative to `cwd` unless already absolute. |
|
|
37
|
-
| `relativePath` | string | no | Stored path shown to ChalkSurf. Defaults to the basename of `path`. |
|
|
38
|
-
|
|
39
|
-
`directory`
|
|
40
|
-
|
|
41
|
-
| Field | Type | Required | Notes |
|
|
42
|
-
| --- | --- | --- | --- |
|
|
43
|
-
| `path` | string | yes | Directory to expand recursively. |
|
|
44
|
-
| `relativeRoot` | string | no | Base directory used to compute stored relative paths. Defaults to `path`. |
|
|
45
|
-
|
|
46
|
-
`url`
|
|
47
|
-
|
|
48
|
-
| Field | Type | Required | Notes |
|
|
49
|
-
| --- | --- | --- | --- |
|
|
50
|
-
| `url` | string | yes | HTTP(S) URL to download before import. |
|
|
51
|
-
| `relativePath` | string | no | Stored path shown to ChalkSurf. Defaults to the filename derived from the URL. |
|
|
52
|
-
|
|
53
|
-
## Command-Specific Fields
|
|
54
|
-
|
|
55
|
-
### Sheet Import
|
|
56
|
-
|
|
57
|
-
Top-level fields:
|
|
58
|
-
|
|
59
|
-
| Field | Type | Required | Notes |
|
|
60
|
-
| --- | --- | --- | --- |
|
|
61
|
-
| `sheets` | array | yes | One or more sheets to import. Each sheet may contain one or more source files. |
|
|
62
|
-
|
|
63
|
-
Normal sheet fields:
|
|
64
|
-
|
|
65
|
-
| Field | Type | Required | Notes |
|
|
66
|
-
| --- | --- | --- | --- |
|
|
67
|
-
| `targetFolderPath` | string \| null | yes | Destination folder for the resulting sheet. Use `null` for the root folder. |
|
|
68
|
-
| `sources` | array | yes | One or more source files that belong to this sheet, in import order. |
|
|
69
|
-
| `title` | string | no | Overrides the imported sheet title. |
|
|
70
|
-
| `translateTo` | string[] | no | Target translation languages. Must be unique and non-empty when present. |
|
|
71
|
-
|
|
72
|
-
Sheet import metadata is sheet-level, not source-level. Do not put `title` or `translateTo` on individual sources inside `sheets[].sources[]`.
|
|
73
|
-
|
|
74
|
-
Source-level `relativePath` is only a source label or filename override. It does not choose the destination folder for grouped sheet imports; `targetFolderPath` is the only destination field.
|
|
75
|
-
|
|
76
|
-
Declared-component sheet fields:
|
|
77
|
-
|
|
78
|
-
Use `components[]` when the same source group contains a known fixed set of component sheets. In this mode, do not put `targetFolderPath`, `title`, or `translateTo` on the sheet itself; put output metadata on each component.
|
|
79
|
-
|
|
80
|
-
| Field | Type | Required | Notes |
|
|
81
|
-
| --- | --- | --- | --- |
|
|
82
|
-
| `sources` | array | yes | One or more source files that contain the declared components. |
|
|
83
|
-
| `components` | array | yes | The explicitly requested component sheets to extract from the shared source group. |
|
|
84
|
-
|
|
85
|
-
Component fields:
|
|
86
|
-
|
|
87
|
-
| Field | Type | Required | Notes |
|
|
88
|
-
| --- | --- | --- | --- |
|
|
89
|
-
| `componentId` | string | yes | Stable key for this requested component. Must match `/^[a-zA-Z0-9_-]{1,80}$/` and be unique within the sheet group. |
|
|
90
|
-
| `description` | string | yes | Matching instructions that identify this component in the source group. |
|
|
91
|
-
| `targetFolderPath` | string \| null | no | Destination folder for this component. Omit or use `null` for the root folder. |
|
|
92
|
-
| `title` | string | no | Overrides the imported component sheet title. |
|
|
93
|
-
| `translateTo` | string[] | no | Target translation languages for this component. Must be unique and non-empty when present. |
|
|
94
|
-
|
|
95
|
-
The model must return an explicit `import` or `not_present` decision for every declared `componentId`. Jobs complete when at least one component is imported and fail when all declared components are `not_present`.
|
|
96
|
-
|
|
97
|
-
Canonical example:
|
|
98
|
-
|
|
99
|
-
- [docs/examples/sheet-import-manifest.json](./examples/sheet-import-manifest.json)
|
|
100
|
-
- [schemas/sheet-import-manifest.schema.json](../schemas/sheet-import-manifest.schema.json)
|
|
101
|
-
|
|
102
|
-
### Exercise Import
|
|
103
|
-
|
|
104
|
-
Top-level fields:
|
|
105
|
-
|
|
106
|
-
| Field | Type | Required | Notes |
|
|
107
|
-
| --- | --- | --- | --- |
|
|
108
|
-
| `sources` | array | yes | One or more import sources. |
|
|
109
|
-
| `exerciseSheetId` | string | no | Default target sheet for the imported exercises. Can still be overridden by `--sheet-id`. |
|
|
110
|
-
| `translateTo` | string[] | no | Target translation languages for every imported exercise. Must be unique and non-empty when present. |
|
|
111
|
-
|
|
112
|
-
Per-source fields:
|
|
113
|
-
|
|
114
|
-
- Only the common source fields are allowed.
|
|
115
|
-
- `title` and source-level `translateTo` are rejected for this command.
|
|
116
|
-
|
|
117
|
-
Canonical example:
|
|
118
|
-
|
|
119
|
-
- [docs/examples/exercise-import-manifest.json](./examples/exercise-import-manifest.json)
|
|
120
|
-
- [schemas/exercise-import-manifest.schema.json](../schemas/exercise-import-manifest.schema.json)
|
|
121
|
-
|
|
122
|
-
### Exercise Solution Import
|
|
123
|
-
|
|
124
|
-
Top-level fields:
|
|
125
|
-
|
|
126
|
-
| Field | Type | Required | Notes |
|
|
127
|
-
| --- | --- | --- | --- |
|
|
128
|
-
| `sources` | array | yes | One or more import sources. |
|
|
129
|
-
| `exerciseId` | string | no | Default target exercise for the imported solution files. The command still requires an exercise id overall, either here or positionally. |
|
|
130
|
-
|
|
131
|
-
Per-source fields:
|
|
132
|
-
|
|
133
|
-
- Only the common source fields are allowed.
|
|
134
|
-
- `title` and `translateTo` are rejected for this command.
|
|
135
|
-
|
|
136
|
-
Canonical example:
|
|
137
|
-
|
|
138
|
-
- [docs/examples/exercise-solution-import-manifest.json](./examples/exercise-solution-import-manifest.json)
|
|
139
|
-
- [schemas/exercise-solution-import-manifest.schema.json](../schemas/exercise-solution-import-manifest.schema.json)
|
|
140
|
-
|
|
141
|
-
### Exercise Sheet Solution Import
|
|
142
|
-
|
|
143
|
-
Top-level fields:
|
|
144
|
-
|
|
145
|
-
| Field | Type | Required | Notes |
|
|
146
|
-
| --- | --- | --- | --- |
|
|
147
|
-
| `sources` | array | yes | One or more source files containing solutions for some or all exercises in the target sheet. |
|
|
148
|
-
| `exerciseSheetId` | string | no | Default target sheet for the imported solution files. The command still requires a sheet id overall, either here or positionally. |
|
|
149
|
-
|
|
150
|
-
Per-source fields:
|
|
151
|
-
|
|
152
|
-
- Only the common source fields are allowed.
|
|
153
|
-
- `title` and `translateTo` are rejected for this command.
|
|
154
|
-
|
|
155
|
-
Canonical example:
|
|
156
|
-
|
|
157
|
-
- [docs/examples/exercise-sheet-solution-import-manifest.json](./examples/exercise-sheet-solution-import-manifest.json)
|
|
158
|
-
- [schemas/exercise-sheet-solution-import-manifest.schema.json](../schemas/exercise-sheet-solution-import-manifest.schema.json)
|
|
159
|
-
|
|
160
|
-
## Validation Notes
|
|
161
|
-
|
|
162
|
-
The CLI validates more than the JSON schema can express on its own:
|
|
163
|
-
|
|
164
|
-
- `sourceId` values must be unique within one manifest.
|
|
165
|
-
- Sheet import `translateTo` values must be unique within one sheet.
|
|
166
|
-
- Sheet import component `componentId` values must be unique within one sheet group.
|
|
167
|
-
- Sheet import components require non-empty descriptions.
|
|
168
|
-
- Exercise import top-level `translateTo` values must be unique.
|
|
169
|
-
- `relativePath` cannot be empty or contain `..`.
|
|
170
|
-
- Sheet import `targetFolderPath` must be `null` or a normalized folder path without `.` or `..` segments.
|
|
171
|
-
- `directory` imports must resolve to at least one file.
|
|
172
|
-
- URL imports must use `http` or `https`.
|
|
173
|
-
|
|
174
|
-
Treat the schema files as a reference format and the CLI as the final validator.
|
|
21
|
+
Import dry runs report SHA-256 fingerprints and byte counts for readable local files in `localSources`. These describe the observed local bytes, not future extraction results. Remote URL bytes remain unknown and are never downloaded by a dry run.
|
package/docs/manual.md
CHANGED
|
@@ -36,7 +36,7 @@ Config resolution rules:
|
|
|
36
36
|
- `--profile` overrides `CHALKSURF_PROFILE`, which overrides the stored default profile.
|
|
37
37
|
- `--base-url` overrides `CHALKSURF_BASE_URL`, which overrides the active profile.
|
|
38
38
|
- `CHALKSURF_TOKEN` overrides the active profile token.
|
|
39
|
-
- `--organization` overrides
|
|
39
|
+
- `--organization` overrides `CHALKSURF_ORGANIZATION_ID`, which overrides the active profile. Content manifests cannot select an organization.
|
|
40
40
|
|
|
41
41
|
## Organization Selection
|
|
42
42
|
|
|
@@ -77,7 +77,7 @@ Import one sheet, override its title, and request an English translation after i
|
|
|
77
77
|
```bash
|
|
78
78
|
chalksurf sheet import ./fixtures/algebra.pdf \
|
|
79
79
|
--title "OKTV 2014 Round 1" \
|
|
80
|
-
--
|
|
80
|
+
--target-language english \
|
|
81
81
|
--wait
|
|
82
82
|
```
|
|
83
83
|
|
|
@@ -95,14 +95,14 @@ Import exercises into an existing sheet:
|
|
|
95
95
|
```bash
|
|
96
96
|
chalksurf exercise import ./fixtures/problem-set.pdf \
|
|
97
97
|
--sheet-id 00000000-0000-4000-8000-000000000001 \
|
|
98
|
-
--
|
|
98
|
+
--target-language english \
|
|
99
99
|
--wait
|
|
100
100
|
```
|
|
101
101
|
|
|
102
102
|
Import a solution into an existing exercise:
|
|
103
103
|
|
|
104
104
|
```bash
|
|
105
|
-
chalksurf exercise
|
|
105
|
+
chalksurf exercise solution import \
|
|
106
106
|
00000000-0000-4000-8000-000000000001 \
|
|
107
107
|
./fixtures/solution.pdf \
|
|
108
108
|
--wait
|
|
@@ -130,7 +130,7 @@ chalksurf quality-issue artifact reconcile --run-dir PATH --json
|
|
|
130
130
|
Import a separate solution file for an existing exercise sheet:
|
|
131
131
|
|
|
132
132
|
```bash
|
|
133
|
-
chalksurf sheet import
|
|
133
|
+
chalksurf sheet solution import \
|
|
134
134
|
00000000-0000-4000-8000-000000000001 \
|
|
135
135
|
./fixtures/sheet-solutions.pdf \
|
|
136
136
|
--wait
|
|
@@ -151,7 +151,7 @@ Use a manifest for multi-source imports or when each resulting sheet needs expli
|
|
|
151
151
|
chalksurf sheet import --manifest ./import.json --wait
|
|
152
152
|
```
|
|
153
153
|
|
|
154
|
-
|
|
154
|
+
Content manifests use `schemaVersion: "v1"`, `operation: "sheet.import"` and `items[]` with unique `itemId` values. Normal items have ordered `sources`, optional `targetFolderPath`, `title` and `targetLanguages`. Files resolve relative to the manifest file; stdin paths use the invocation directory. Component and authoritative language groups are described in the [manifest reference](./manifest.md).
|
|
155
155
|
|
|
156
156
|
## Working With Jobs
|
|
157
157
|
|
|
@@ -179,17 +179,25 @@ Wait on one or more jobs later:
|
|
|
179
179
|
chalksurf job wait job_123 job_124
|
|
180
180
|
```
|
|
181
181
|
|
|
182
|
-
`--wait`
|
|
182
|
+
A successful `--wait` observes the primary import jobs and authoritative translation-import children. Automatically generated translations and metadata aftercare remain separate follow-ups; inspect `result.observation` and job IDs. A timeout, failed observation or interruption preserves known results and does not cancel remote work.
|
|
183
183
|
|
|
184
184
|
Queue translations for existing resources:
|
|
185
185
|
|
|
186
186
|
```bash
|
|
187
|
-
chalksurf exercise
|
|
188
|
-
chalksurf sheet
|
|
187
|
+
chalksurf exercise translation generate 00000000-0000-4000-8000-000000000001 --target-language english
|
|
188
|
+
chalksurf sheet translation generate 00000000-0000-4000-8000-000000000002 --target-language english --source-language hungarian
|
|
189
189
|
```
|
|
190
190
|
|
|
191
191
|
Add `--wait` to either translate command to wait for the queued translation job or jobs to finish.
|
|
192
192
|
|
|
193
|
+
Import an authoritative translation from source documents into an existing sheet:
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
chalksurf sheet translation import 00000000-0000-4000-8000-000000000002 ./official-german-paper.pdf --source-language hungarian --target-language german --wait
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
This accepts a complete ready source language and a distinct missing or failed target language. It starts a fresh import job; successful sibling translations remain untouched.
|
|
200
|
+
|
|
193
201
|
## Searching From The CLI
|
|
194
202
|
|
|
195
203
|
Search commands default to `--ownership own`, which means resources in the selected organization.
|
|
@@ -245,8 +253,8 @@ chalksurf exercise get 00000000-0000-4000-8000-000000000002 --json
|
|
|
245
253
|
Inspect sheet version history and one stored snapshot:
|
|
246
254
|
|
|
247
255
|
```bash
|
|
248
|
-
chalksurf sheet
|
|
249
|
-
chalksurf sheet version 00000000-0000-4000-8000-000000000001 00000000-0000-4000-8000-000000000003 --json
|
|
256
|
+
chalksurf sheet version list 00000000-0000-4000-8000-000000000001 --json
|
|
257
|
+
chalksurf sheet version get 00000000-0000-4000-8000-000000000001 00000000-0000-4000-8000-000000000003 --json
|
|
250
258
|
```
|
|
251
259
|
|
|
252
260
|
List sheet issues that are useful for repair workflows:
|
|
@@ -268,34 +276,28 @@ Patch an exercise with an optimistic update precondition:
|
|
|
268
276
|
```bash
|
|
269
277
|
chalksurf exercise update 00000000-0000-4000-8000-000000000002 \
|
|
270
278
|
--expected-updated-at 2026-01-01T00:00:00.000Z \
|
|
271
|
-
--
|
|
272
|
-
|
|
279
|
+
--input - --json <<'JSON'
|
|
280
|
+
{"translations":{"english":{"exercise_text":"Find $x^2$."}}}
|
|
281
|
+
JSON
|
|
273
282
|
```
|
|
274
283
|
|
|
275
284
|
Write commands return a receipt with the affected resource, changed paths, warnings, and operation-specific details. Fetch the resource first and use its current `updated_at` value for patch commands.
|
|
276
285
|
|
|
277
|
-
|
|
286
|
+
Repeated sheet patches use a reviewed plan. Series-assignment changes retain their administrator requirement:
|
|
278
287
|
|
|
279
288
|
```bash
|
|
280
289
|
chalksurf sheet series list --subject math --json
|
|
281
|
-
chalksurf sheet
|
|
282
|
-
|
|
283
|
-
chalksurf
|
|
284
|
-
|
|
290
|
+
chalksurf sheet update --manifest batch-001.json --dry-run --plan-out batch-001.plan.json --json
|
|
291
|
+
chalksurf plan show batch-001.plan.json --json
|
|
292
|
+
chalksurf plan apply batch-001.plan.json --result-file batch-001.apply.json --json
|
|
293
|
+
chalksurf plan verify batch-001.plan.json --result-file batch-001.verify.json --json
|
|
285
294
|
```
|
|
286
295
|
|
|
287
|
-
|
|
296
|
+
A saved plan binds the exact request, environment, organization, targets and effects. Updates to multiple sheets remain atomic; exercise updates retain explicit best-effort outcomes. `--plan-out` requires `--dry-run`. Only updates and solution/description generation support executable plans. A result envelope is not a plan, and old bulk-update envelopes must be regenerated from the original input.
|
|
288
297
|
|
|
289
|
-
|
|
298
|
+
Verification reports `desired`, `original`, `conflicting` or `unreadable` current update state; it does not establish authorship. For generation, verification reads recorded acceptance and job outcomes. Never retry a write because a lookup failed. See [content operations](./content-operations.md) for exact resend and recovery.
|
|
290
299
|
|
|
291
|
-
|
|
292
|
-
chalksurf sheet bulk-update verify \
|
|
293
|
-
--input batch-001.apply.json --result-file batch-001.verify.result.json --json
|
|
294
|
-
```
|
|
295
|
-
|
|
296
|
-
An `applied` result means the intended target is already present. `pending` means the original preconditions still match but the target is absent; rerun dry-run before a later apply. Inspect `conflicting` and `error` results. Never retry an uncertain apply blindly.
|
|
297
|
-
|
|
298
|
-
For `sheet list`, `sheet bulk-update`, and `sheet bulk-update verify`, `--result-file` stores the complete JSON envelope while stdout reports only a compact summary. Result files are created privately and exclusively: an existing destination is never overwritten, so use a new path for every attempt. If artifact publication fails after the server confirms an apply, the CLI returns the complete confirmed response on stdout with a warning and a successful exit code. Preserve that response and do not retry the apply.
|
|
300
|
+
Every operational command accepts `--result-file PATH`, a new private file containing the complete terminal envelope. Stdout then contains the absolute artifact path. Destination preflight failures stop execution; publication failure after a response prints the complete fallback and preserves the command's exit code.
|
|
299
301
|
|
|
300
302
|
Manage folders:
|
|
301
303
|
|
|
@@ -327,6 +329,20 @@ Use JSON mode when you need exact machine-readable output:
|
|
|
327
329
|
chalksurf job wait job_123 --json
|
|
328
330
|
```
|
|
329
331
|
|
|
332
|
+
Generate solutions and descriptions, or manage jobs directly:
|
|
333
|
+
|
|
334
|
+
```bash
|
|
335
|
+
chalksurf exercise solution generate EXERCISE_ID --dry-run --json
|
|
336
|
+
chalksurf sheet solution generate SHEET_ID --json
|
|
337
|
+
chalksurf exercise description generate --sheet-id SHEET_ID --dry-run --plan-out descriptions.json --json
|
|
338
|
+
chalksurf plan apply descriptions.json --wait --json
|
|
339
|
+
chalksurf job list --request-id REQUEST_ID --json
|
|
340
|
+
chalksurf job cancel JOB_ID --wait --json
|
|
341
|
+
chalksurf job dismiss JOB_ID --json
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
Use `--replace-existing` to acknowledge replacing solution fields. Use `--allow-shared-exercise-update` only after reviewing shared usage. Draft translation uses `exercise translation generate --draft --input FILE` and never persists content. Published language removal uses `sheet translation remove SHEET_ID --target-language LANGUAGE --confirm-resource-id SHEET_ID`; pending work is cancelled with `job cancel`.
|
|
345
|
+
|
|
330
346
|
Further reference:
|
|
331
347
|
|
|
332
348
|
- [Agent and Codex guide](./agents.md)
|
package/docs/mcp.md
CHANGED
|
@@ -8,7 +8,7 @@ ChalkSurf exposes a remote MCP endpoint for agent workflows that need the same c
|
|
|
8
8
|
- Protocols: modern `2026-07-28` and stateless legacy `2025-11-25` are both supported on the same endpoint.
|
|
9
9
|
- Authentication: OAuth access tokens issued through the ChalkSurf MCP authorization flow.
|
|
10
10
|
- CLI tokens and browser session tokens are rejected on `/mcp`.
|
|
11
|
-
- Tools advertise
|
|
11
|
+
- Tools advertise the single `chalksurf:mcp` resource scope during OAuth authorization. The editable MCP grant's current
|
|
12
12
|
per-organization permission is the authoritative runtime read/write boundary, so changing the grant does not require
|
|
13
13
|
issuing a new access token.
|
|
14
14
|
- Organization-scoped tools require an explicit `organizationId` argument for normal execution.
|
|
@@ -29,9 +29,11 @@ MCP clients should use their built-in tool listing/search. ChalkSurf does not ex
|
|
|
29
29
|
|
|
30
30
|
The MCP tools and CLI commands are backed by the same agent resource contracts in `packages/shared/src/agent-tools`.
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
The core MCP exercise, sheet, and folder search/list/get tools return their primary structured result plus a top-level `resources` array of absolute links. `get_exercise_usage` links the sheets in its usage result. Nested matching sources, embedded exercises, versions, issues, and metadata are not linked. Empty primary results return `resources: []` without an extra link block. These sidecars are MCP-only; equivalent CLI and direct API read payloads are unchanged.
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
Write tools return a structured `receipt`:
|
|
35
|
+
|
|
36
|
+
- `resource`: the resource type and ID affected by the write, plus an absolute `url` for a surviving navigable exercise, sheet, or folder
|
|
35
37
|
- `operation`: the stable operation name, such as `update_exercise`
|
|
36
38
|
- `changedPaths`: field paths changed by the operation
|
|
37
39
|
- `precondition`: optimistic update status, including `expectedUpdatedAt` and `actualUpdatedAt`
|
|
@@ -40,6 +42,8 @@ Read tools return structured resource data. Write tools return a structured `rec
|
|
|
40
42
|
|
|
41
43
|
Treat write receipts as an agent audit log. They are suitable for user-visible summaries after an agent edits a sheet.
|
|
42
44
|
|
|
45
|
+
The same absolute links are repeated in ordinary MCP text so clients can include them in conversation. Completed jobs returned by `list_jobs`, `get_job`, and `wait_for_jobs` contain a plural `resources` array for their resulting exercises or sheets; non-completed or malformed job results use an empty array. Browser links include `organizationId` as a navigation hint. ChalkSurf waits for the signed-in user and memberships before applying it, ignores and clears inaccessible hints, and preserves it through login when the browser is anonymous. The query parameter does not grant access; resource endpoints remain authoritative. Delete receipts and the legacy singular `bulk_update_sheets` receipt resource deliberately have no URL.
|
|
46
|
+
|
|
43
47
|
Exercise content writes are stricter for agents than for the human UI. `create_exercise` validates all submitted normalized exercise translation fields before writing. `update_exercise` validates only translation fields explicitly present in `patch.translations`; omitted invalid fields do not block unrelated partial updates.
|
|
44
48
|
|
|
45
49
|
Successful exercise create/update receipts include `details.latexValidation` with one of these scopes:
|
|
@@ -73,62 +77,63 @@ Use `error.agentErrorDetails.results[].patchPath` and `validation.issues[]` to r
|
|
|
73
77
|
|
|
74
78
|
## Tool Surface
|
|
75
79
|
|
|
76
|
-
| Tool | Permission | Purpose
|
|
77
|
-
| ----------------------------------- | ---------- |
|
|
78
|
-
| `get_auth_status` | read | Confirm the authenticated user and return the complete current organization catalog.
|
|
79
|
-
| `list_organizations` | read | Return the complete current organizations usable through the MCP grant and membership.
|
|
80
|
-
| `search_exercises` | read | Search exercises by text, labels, status, ownership, age, difficulty, or semantic query.
|
|
81
|
-
| `get_exercise` | read | Fetch full details for one visible exercise.
|
|
82
|
-
| `list_exercise_labels` | read | List the canonical exercise label taxonomy agents may write to exercises.
|
|
83
|
-
| `get_exercise_usage` | read | Inspect which sheets use one visible exercise.
|
|
84
|
-
| `list_quality_issues` | read | List active findings for organization-owned exercises with bounded selectors and keyset pagination.
|
|
85
|
-
| `figure_get_capabilities` | read | Inspect supported semantic 2D figure objects, construction definitions, assertions, limits, and snippets.
|
|
86
|
-
| `figure_render_draft` | read | Render a semantic figure draft to SVG/PNG metadata, PNG image content, diagnostics, assertions, and review hints.
|
|
87
|
-
| `upload_exercise_figure` | write | Upload and attach one reviewed image from a ChatGPT file parameter, HTTPS image, base64 image, or rendered figure to an exercise.
|
|
88
|
-
| `create_exercise` | write | Create one exercise in the selected organization.
|
|
89
|
-
| `copy_exercise` | write | Copy one visible exercise into the selected organization.
|
|
90
|
-
| `delete_exercise` | write | Soft-delete one unused writable exercise after `updated_at` and exact-ID confirmation checks.
|
|
91
|
-
| `update_exercise` | write | Patch exercise fields with an `updated_at` precondition and shared-usage acknowledgement.
|
|
92
|
-
| `resolve_quality_issue` | write | Resolve one active finding after checking the exercise evidence timestamp.
|
|
93
|
-
| `dismiss_quality_issue` | write | Dismiss one active false positive after checking the exercise evidence timestamp.
|
|
94
|
-
| `set_exercise_visibility` | write | Make one writable exercise public or private when visibility controls are enabled.
|
|
95
|
-
| `generate_exercise_translation_job` | write | Queue translation generation for one writable exercise.
|
|
96
|
-
| `import_exercise` | write | Queue an exercise import from ChatGPT file parameters or HTTPS URLs.
|
|
97
|
-
| `import_exercise_solution` | write | Queue a solution import for one exercise.
|
|
98
|
-
| `search_sheets` | read | Search visible sheets by text, subject, ownership, readiness, series, or edition year.
|
|
99
|
-
| `list_sheets` | read | List sheets owned by the selected organization, including folder paths and current series assignments.
|
|
100
|
-
| `get_sheet` | read | Fetch full details for one visible sheet.
|
|
101
|
-
| `list_sheet_series` | read | List the authoritative sheet-series hierarchy and valid assignment paths.
|
|
102
|
-
| `list_sheet_versions` | read | List version history for one sheet owned by the granted organization.
|
|
103
|
-
| `get_sheet_version` | read | Fetch one owned sheet version snapshot with referenced exercise details.
|
|
104
|
-
| `get_sheet_issues` | read | Fetch actionable sheet issues: invalid LaTeX, missing translations, missing solutions, and missing scores.
|
|
105
|
-
| `create_sheet` | write | Create one exercise sheet in the selected organization.
|
|
106
|
-
| `copy_sheet` | write | Copy a visible sheet, either keeping exercise references or copying all visible exercises.
|
|
107
|
-
| `delete_sheet` | write | Soft-delete one writable sheet after `updated_at` and exact-ID confirmation checks.
|
|
108
|
-
| `update_sheet` | write | Patch sheet metadata with an `updated_at` precondition.
|
|
109
|
-
| `bulk_update_sheets` | write | Dry-run or atomically apply up to 100 sheet patches using a confirmation digest.
|
|
110
|
-
| `verify_bulk_sheet_updates` | write | Read back up to 100 exact sheet-patch targets after an uncertain bulk apply response.
|
|
111
|
-
| `set_sheet_visibility` | write | Make one writable sheet public or private when visibility controls are enabled.
|
|
112
|
-
| `append_exercises_to_sheet` | write | Append existing visible exercises to the end of one writable sheet.
|
|
113
|
-
| `
|
|
114
|
-
| `list_folders` | read | List sheet folders in the selected organization.
|
|
115
|
-
| `create_folder` | write | Create a sheet folder.
|
|
116
|
-
| `rename_folder` | write | Rename a sheet folder.
|
|
117
|
-
| `delete_folder` | write | Delete one empty sheet folder after exact-ID confirmation.
|
|
118
|
-
| `validate_latex_snippets` | read | Validate proposed LaTeX snippets before writing.
|
|
119
|
-
| `import_sheet` | write | Queue sheet imports from ChatGPT file parameters or HTTPS URLs.
|
|
120
|
-
| `import_sheet_solutions` | write | Queue solution import for an existing sheet.
|
|
121
|
-
| `
|
|
122
|
-
| `
|
|
123
|
-
| `
|
|
124
|
-
| `
|
|
125
|
-
| `
|
|
80
|
+
| Tool | Permission | Purpose |
|
|
81
|
+
| ----------------------------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------- |
|
|
82
|
+
| `get_auth_status` | read | Confirm the authenticated user and return the complete current organization catalog. |
|
|
83
|
+
| `list_organizations` | read | Return the complete current organizations usable through the MCP grant and membership. |
|
|
84
|
+
| `search_exercises` | read | Search exercises by text, labels, status, ownership, age, difficulty, or semantic query. |
|
|
85
|
+
| `get_exercise` | read | Fetch full details for one visible exercise. |
|
|
86
|
+
| `list_exercise_labels` | read | List the canonical exercise label taxonomy agents may write to exercises. |
|
|
87
|
+
| `get_exercise_usage` | read | Inspect which sheets use one visible exercise. |
|
|
88
|
+
| `list_quality_issues` | read | List active findings for organization-owned exercises with bounded selectors and keyset pagination. |
|
|
89
|
+
| `figure_get_capabilities` | read | Inspect supported semantic 2D figure objects, construction definitions, assertions, limits, and snippets. |
|
|
90
|
+
| `figure_render_draft` | read | Render a semantic figure draft to SVG/PNG metadata, PNG image content, diagnostics, assertions, and review hints. |
|
|
91
|
+
| `upload_exercise_figure` | write | Upload and attach one reviewed image from a ChatGPT file parameter, HTTPS image, base64 image, or rendered figure to an exercise. |
|
|
92
|
+
| `create_exercise` | write | Create one exercise in the selected organization. |
|
|
93
|
+
| `copy_exercise` | write | Copy one visible exercise into the selected organization. |
|
|
94
|
+
| `delete_exercise` | write | Soft-delete one unused writable exercise after `updated_at` and exact-ID confirmation checks. |
|
|
95
|
+
| `update_exercise` | write | Patch exercise fields with an `updated_at` precondition and shared-usage acknowledgement. |
|
|
96
|
+
| `resolve_quality_issue` | write | Resolve one active finding after checking the exercise evidence timestamp. |
|
|
97
|
+
| `dismiss_quality_issue` | write | Dismiss one active false positive after checking the exercise evidence timestamp. |
|
|
98
|
+
| `set_exercise_visibility` | write | Make one writable exercise public or private when visibility controls are enabled. |
|
|
99
|
+
| `generate_exercise_translation_job` | write | Queue translation generation for one writable exercise. |
|
|
100
|
+
| `import_exercise` | write | Queue an exercise import from ChatGPT file parameters or HTTPS URLs. |
|
|
101
|
+
| `import_exercise_solution` | write | Queue a solution import for one exercise. |
|
|
102
|
+
| `search_sheets` | read | Search visible sheets by text, subject, ownership, readiness, series, or edition year. |
|
|
103
|
+
| `list_sheets` | read | List sheets owned by the selected organization, including folder paths and current series assignments. |
|
|
104
|
+
| `get_sheet` | read | Fetch full details for one visible sheet. |
|
|
105
|
+
| `list_sheet_series` | read | List the authoritative sheet-series hierarchy and valid assignment paths. |
|
|
106
|
+
| `list_sheet_versions` | read | List version history for one sheet owned by the granted organization. |
|
|
107
|
+
| `get_sheet_version` | read | Fetch one owned sheet version snapshot with referenced exercise details. |
|
|
108
|
+
| `get_sheet_issues` | read | Fetch actionable sheet issues: invalid LaTeX, missing translations, missing solutions, and missing scores. |
|
|
109
|
+
| `create_sheet` | write | Create one exercise sheet in the selected organization. |
|
|
110
|
+
| `copy_sheet` | write | Copy a visible sheet, either keeping exercise references or copying all visible exercises. |
|
|
111
|
+
| `delete_sheet` | write | Soft-delete one writable sheet after `updated_at` and exact-ID confirmation checks. |
|
|
112
|
+
| `update_sheet` | write | Patch sheet metadata with an `updated_at` precondition. |
|
|
113
|
+
| `bulk_update_sheets` | write | Dry-run or atomically apply up to 100 sheet patches using a confirmation digest. |
|
|
114
|
+
| `verify_bulk_sheet_updates` | write | Read back up to 100 exact sheet-patch targets after an uncertain bulk apply response. |
|
|
115
|
+
| `set_sheet_visibility` | write | Make one writable sheet public or private when visibility controls are enabled. |
|
|
116
|
+
| `append_exercises_to_sheet` | write | Append existing visible exercises to the end of one writable sheet. |
|
|
117
|
+
| `generate_sheet_translation` | write | Queue translation generation for one writable exercise sheet. |
|
|
118
|
+
| `list_folders` | read | List sheet folders in the selected organization. |
|
|
119
|
+
| `create_folder` | write | Create a sheet folder. |
|
|
120
|
+
| `rename_folder` | write | Rename a sheet folder. |
|
|
121
|
+
| `delete_folder` | write | Delete one empty sheet folder after exact-ID confirmation. |
|
|
122
|
+
| `validate_latex_snippets` | read | Validate proposed LaTeX snippets before writing. |
|
|
123
|
+
| `import_sheet` | write | Queue sheet imports from ChatGPT file parameters or HTTPS URLs. |
|
|
124
|
+
| `import_sheet_solutions` | write | Queue solution import for an existing sheet. |
|
|
125
|
+
| `import_sheet_translation` | write | Import one authoritative translation into an existing sheet. |
|
|
126
|
+
| `list_jobs` | read | List jobs in the granted organization. |
|
|
127
|
+
| `get_job` | read | Fetch one job. |
|
|
128
|
+
| `wait_for_jobs` | read | Wait for one or more jobs to complete. |
|
|
129
|
+
| `send_user_feedback` | read | Send user-consented product feedback, bug reports, or blocked-request reports. |
|
|
130
|
+
| `send_agent_feedback` | read | Send agent-observed API, MCP, CLI, or documentation feedback. |
|
|
126
131
|
|
|
127
132
|
For `create_sheet`, pass `folderId` to create the sheet in a target folder. Omit it or pass `null` to create the sheet at the organization root.
|
|
128
133
|
|
|
129
|
-
|
|
134
|
+
Bulk sheet updates require write access and sheets owned by the selected organization. Requests containing any `patch.seriesAssignments` field are additionally restricted to admin users; `expectedSeriesAssignments` alone remains available as a non-mutating precondition for ordinary bulk updates. For series writes, use `list_sheet_series`, then call `bulk_update_sheets` with `mode: "dry_run"`. Apply the unchanged batch with the returned `confirmationDigest`; no idempotency key or separate idempotency table is used. CLI `sheet bulk-update`, `sheet bulk-update apply --dry-run-result FILE`, and `sheet bulk-update verify` provide the same operation and recovery contracts. Applying a complete dry-run result artifact, CLI file/stdin input, the global `--result-file` artifact publisher, and `sheet list --all` are local orchestration conveniences rather than MCP parameters. MCP inventory callers can use `list_sheets.afterId` with the previous page's last sheet ID for keyset pagination.
|
|
130
135
|
|
|
131
|
-
If the apply response is lost or uncertain, pass the exact same `updates` array to `verify_bulk_sheet_updates`. It compares the normalized target fields before checking the original preconditions, so a completed apply is reported as `applied` even though its write changed `updated_at`. A result is `pending` when target fields still differ and the preconditions still match, `conflicting` when target fields differ and a precondition changed, and `error` when the target cannot be read or validated. The verifier performs no writes and creates no agent audit entry
|
|
136
|
+
If the apply response is lost or uncertain, pass the exact same `updates` array to `verify_bulk_sheet_updates`. It compares the normalized target fields before checking the original preconditions, so a completed apply is reported as `applied` even though its write changed `updated_at`. A result is `pending` when target fields still differ and the preconditions still match, `conflicting` when target fields differ and a precondition changed, and `error` when the target cannot be read or validated. The verifier performs no writes and creates no agent audit entry. It requires an organization write grant and the `chalksurf:mcp` OAuth scope, plus administrator access when any verified update contains `patch.seriesAssignments`.
|
|
132
137
|
|
|
133
138
|
The bulk receipt's singular `resource` remains populated for backward compatibility. It is not a complete attribution: use `details.sheetIds` and the per-sheet results for the authoritative affected set. ChalkSurf omits that compatibility value from durable bulk audit primary-resource attribution and displays the validated resource count instead.
|
|
134
139
|
|
|
@@ -140,7 +145,7 @@ Figure tools are available for agents to create and attach figures to exercises.
|
|
|
140
145
|
|
|
141
146
|
### File Parameters
|
|
142
147
|
|
|
143
|
-
ChatGPT file uploads are advertised with `_meta["openai/fileParams"]`. For `import_exercise`, `import_exercise_solution`, `import_sheet`, and `
|
|
148
|
+
ChatGPT file uploads are advertised with `_meta["openai/fileParams"]`. For `import_exercise`, `import_exercise_solution`, `import_sheet`, `import_sheet_solutions`, and `import_sheet_translation`, ChatGPT should pass uploaded files in top-level `file_id_N` arguments. The field names are model-facing: ChatGPT receives file IDs for those fields, then the harness passes ChalkSurf resolved file objects:
|
|
144
149
|
|
|
145
150
|
```json
|
|
146
151
|
{
|
|
@@ -167,7 +172,7 @@ Generic MCP clients should pass absolute HTTPS URLs in `sourceUrls` for import t
|
|
|
167
172
|
|
|
168
173
|
No MCP tool currently transfers resources between organizations.
|
|
169
174
|
|
|
170
|
-
`send_user_feedback` and `send_agent_feedback` are not read-only operations, but
|
|
175
|
+
`send_user_feedback` and `send_agent_feedback` are not read-only operations, but their application permission remains `read` because they do not mutate ChalkSurf exercises, sheets, or folders. Like every MCP tool, they require the `chalksurf:mcp` OAuth resource scope. Use `send_user_feedback` only after the user explicitly agrees to send feedback. Use `send_agent_feedback` when the agent itself observes inconsistent behavior, inaccurate docs, or missing agent-facing API coverage.
|
|
171
176
|
|
|
172
177
|
## Common Workflows
|
|
173
178
|
|