Format Contents API: read the whole package, commit many files at once

Read a Sume Format package with ?recursive=1 and write several files as one commit and one version bump. A change set, not the package; deletes stay separate.

5 min readSume
All posts

Add ?recursive=1 to GET /v1/formats/{handle}/{slug}/contents to read every file in a Sume Format package, with bodies, in one request. To write several files, PUT to the package root with a files list: it lands as one commit, one version bump and one new package_sha, or not at all.

Both calls are in the Contents API docs, which model them on GitHub's Contents API. This post covers the two calls an agent that edits Formats uses most.

How do I read the whole package?

Listing the root and fetching each path is one request per file. The recursive listing returns every row as a file with its base64 content, sorted by path, and no dir rows, since the directories are the paths. recursive=true works too; anything else is the plain root listing. The sha on each row is the same precondition a write takes, so one recursive read is enough to start editing.

curl -sS "https://api.sume.com/v1/formats/acme/live-commerce/contents?recursive=1" \
  -H "Authorization: Bearer $SUME_API_KEY" \
  | jq -r '.data[] | "\(.path) \(.sha)"'

How do I commit several files at once?

Send message and a files list to the root. Each entry follows the single-file rules: content is the whole file base64-encoded, and sha is required when the path exists and omitted to create it.

curl -sS -X PUT "https://api.sume.com/v1/formats/acme/live-commerce/contents" \
  -H "Authorization: Bearer $SUME_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "message": "edit plan + add note",
    "files": [
      { "path": "references/plan.md", "content": "IyBQbGFuCg==", "sha": "3f7b1c0d9e2a4b6c8d0e1f2a3b4c5d6e7f809a1b" },
      { "path": "references/new-note.md", "content": "IyBOZXcK" }
    ]
  }'

What are the rules of a batch?

files is a change set, not the package. Paths the Format holds but the body does not name are kept exactly as they are, so editing two of twelve files never risks the other ten. Deletion is not expressible in a batch: remove a file with DELETE .../contents/{path}, which takes message and sha.

If any entry's sha is stale, or the resulting package breaks a rule, nothing is committed. A batch may name at most 1000 paths. For a guard on the whole package rather than each file, add the If-Match header with the package sha; see If-Match edits.

What may a package contain?

The same rules the dashboard editor enforces. A rejected path answers skill_path_invalid and spells the allowlist back.

Package rules from the Contents API docs (read 2026-10-02).
RuleValue
Entry fileSKILL.md at the root, required, cannot be deleted; frontmatter name must equal the slug
LayoutRoot, or one directory deep under references/ or agents/
File namesMatch ^[A-Za-z0-9][A-Za-z0-9._-]*$
Extensions.md, .json, .yaml, .yml, .txt
SizeAt most 100 MiB per file and per package

What does this API not do?

It is authoring, not execution: editing a package never touches a run already in flight, since each run reads the package it started with. There is no public git endpoint or clone URL, and reverting, blame and history browsing are not part of this surface yet. Service-account keys cannot create or edit packages, and a write needs formats:write. A failed history write answers 503 format_git_unavailable and saves nothing, so retrying is safe.

How do these calls fit an agent loop?

A coding agent that edits a Format follows one loop: read the package once with recursive=1, keep each file's sha and the Format's package_sha, plan the edit against that snapshot, then write the change set. If the package moved in between, an If-Match write is refused with 409 format_package_sha_mismatch and error.details.package_sha carries the current one, so you can re-read and retry in one round trip.

  • Create the Format with POST /v1/formats; it commits a minimal valid SKILL.md immediately.
  • Keep package_sha and contents_url from the reply for your next write.
  • A stale per-file sha is 409 format_content_sha_mismatch; a missing one on an existing path is 409 format_content_sha_required.
  • A slug your workspace already uses is 409 skill_slug_taken, and one a Format by Sume holds is 409 skill_slug_reserved.

Sources

Related posts

More in Formats

All Formats posts

Written by Sume