Posting here as the public-facing SDK repo — happy to re-route if the canonical SKILL.md source lives elsewhere.
While scripting a bulk comment/reply loop (14 comment.reply + comment.resolve ops) against a hosted Proof doc via the agent API (/api/agent/<slug>/ops), I hit four shell-level gotchas that aren't covered by the SKILL.md served at https://www.proofeditor.ai/proof.SKILL.md. Each one fails silently or with an obscure error rather than a clean API error.
Worth a short "Shell Patterns" section in the skill doc, or a linked appendix — authors of agent loops keep rediscovering these.
1. .marks is an object, not an array
The /state and /snapshot response's marks field is keyed by markId, not indexed. jq '.marks[0]' fails with Cannot index object with number. MarkIds look like m1776098130482_1 (comments) or authored:human:<name>:<range> (text anchors).
# Wrong
jq '.marks[0]' state.json
# Right
jq '.marks | to_entries[]' state.json
2. for row in $(jq -c '.[]' file) word-splits JSON
Bash splits $(...) on whitespace, including spaces inside JSON string values. Any op payload with a space in text or content fragments across loop iterations. Use a while-read pipe:
jq -c '.[]' ops.json | while IFS= read -r row; do
curl ... -d "$row"
done
3. baseToken rotates per mutation — refetch inside loops
The current SKILL.md documents baseToken and the 409 BASE_TOKEN_REQUIRED retry path well. The missing piece: for a loop of N ops, a single upfront fetch of mutationBase.token from /snapshot goes stale after op 1 and ops 2..N all fail with Document changed since baseToken until you refetch. Worth calling out explicitly as "refetch per iteration for bulk loops" alongside the existing retry-on-409 guidance.
4. jq parse failure on the response ≠ API failure
Op responses occasionally contain control characters (U+0000–U+001F) that break jq parsing with Invalid string: control characters ... must be escaped. The server-side op may have landed fine. Recommended pattern: fall back on parse failure and verify against /state rather than trusting the parse exit code.
RESULT=$(curl -sS -X POST ".../ops" --data @op.json 2>/dev/null)
STATUS=$(echo "$RESULT" | jq -r 'if .ok == true then "ok" elif .error then .error else "unknown" end' 2>/dev/null || echo "parse-fail-check-state")
# Then re-read /state to confirm the op landed
Happy to open a PR
Can you point me at the canonical source for the SKILL.md served at proofeditor.ai/proof.SKILL.md so I can put up a PR with these as a new section? I couldn't find an obvious match in this repo's docs/proof.SKILL.md — that file describes a /documents/<slug>/edit/v2 + baseRevision API surface rather than the agent API my scripting session used, which suggests the hosted SKILL.md comes from somewhere else.
Reproduced on hosted Proof, 2026-04-13.
Posting here as the public-facing SDK repo — happy to re-route if the canonical SKILL.md source lives elsewhere.
While scripting a bulk comment/reply loop (14
comment.reply+comment.resolveops) against a hosted Proof doc via the agent API (/api/agent/<slug>/ops), I hit four shell-level gotchas that aren't covered by the SKILL.md served at https://www.proofeditor.ai/proof.SKILL.md. Each one fails silently or with an obscure error rather than a clean API error.Worth a short "Shell Patterns" section in the skill doc, or a linked appendix — authors of agent loops keep rediscovering these.
1.
.marksis an object, not an arrayThe
/stateand/snapshotresponse'smarksfield is keyed by markId, not indexed.jq '.marks[0]'fails withCannot index object with number. MarkIds look likem1776098130482_1(comments) orauthored:human:<name>:<range>(text anchors).2.
for row in $(jq -c '.[]' file)word-splits JSONBash splits
$(...)on whitespace, including spaces inside JSON string values. Any op payload with a space intextorcontentfragments across loop iterations. Use a while-read pipe:3.
baseTokenrotates per mutation — refetch inside loopsThe current SKILL.md documents
baseTokenand the409 BASE_TOKEN_REQUIREDretry path well. The missing piece: for a loop of N ops, a single upfront fetch ofmutationBase.tokenfrom/snapshotgoes stale after op 1 and ops 2..N all fail withDocument changed since baseTokenuntil you refetch. Worth calling out explicitly as "refetch per iteration for bulk loops" alongside the existing retry-on-409 guidance.4.
jqparse failure on the response ≠ API failureOp responses occasionally contain control characters (U+0000–U+001F) that break
jqparsing withInvalid string: control characters ... must be escaped. The server-side op may have landed fine. Recommended pattern: fall back on parse failure and verify against/staterather than trusting the parse exit code.Happy to open a PR
Can you point me at the canonical source for the SKILL.md served at
proofeditor.ai/proof.SKILL.mdso I can put up a PR with these as a new section? I couldn't find an obvious match in this repo'sdocs/proof.SKILL.md— that file describes a/documents/<slug>/edit/v2+baseRevisionAPI surface rather than the agent API my scripting session used, which suggests the hosted SKILL.md comes from somewhere else.Reproduced on hosted Proof, 2026-04-13.