Format package files: which types and paths the Contents API accepts
A Sume Format package accepts only .md, .json, .yaml, .yml and .txt files, one folder deep, with SKILL.md required. The full rule list and the error you get.

A Sume Format package may contain only .md, .json, .yaml, .yml and .txt files. SKILL.md at the package root is required, and every other file must sit at the root or one directory level under references/ or agents/. If you send a path that breaks the rules, the Contents API commits nothing and answers skill_path_invalid with the full allowlist.
The rules in one table
These are the rules the Contents API enforces, and the dashboard editor enforces the same ones.
| Rule | Detail |
|---|---|
| Entry file | SKILL.md at the root; required; cannot be deleted |
name in frontmatter | Must equal the Format's slug |
| Depth | Root, or one level under references/ or agents/ |
| Path form | No .., not absolute |
| File name pattern | ^[A-Za-z0-9][A-Za-z0-9._-]*$; cannot start with _ or . |
| Allowed types | .md, .json, .yaml, .yml, .txt |
| Size | 100 MiB per file and 100 MiB per package |
| Batch | At most 1000 paths in one files change set |
What this means in practice
You cannot ship an image, a font or a video inside the package. Put reference text, brand notes, shot lists and JSON examples in references/, and pass media as URLs through attachments or input when you call the Format. A file named _notes.md or .env fails the name pattern, so rename it before you write.
The write is all or nothing. A PUT to the package root with a files list commits every file as one commit or none of them. A failed sha check on one entry also stops the batch.
Writing a note
The request below creates references/brand-notes.md. content is the file body in base64. Because the path is new, no sha is sent; for an existing path you must send the current sha, or you get 409 format_content_sha_required. The handle and slug are placeholders for a Format your key owns, and the key needs formats:write.
curl -sS -X PUT \
"https://api.sume.com/v1/formats/acme/event-recap/contents/references/brand-notes.md" \
-H "Authorization: Bearer $SUME_API_KEY" \
-H "Content-Type: application/json" \
-d '{"message": "add brand notes", "content": "IyBCcmFuZCBub3RlcwoK"}'
When a write is refused
Three answers come up most. skill_path_invalid means a path or type broke a rule. skill_frontmatter_invalid means the SKILL.md header is wrong, for example a name that differs from the slug. skill_limit_exceeded means a size or count limit. Read the response before you retry; none of them is fixed by repeating the same request.
Planning the layout
A layout that stays inside the rules is simple. Keep SKILL.md short and procedural: what the Format does, what it reads from input, and the order of steps. Put long reference material in references/ as .md or .txt, and put examples of the output shape in .json. The agents/ folder is also allowed, one level deep.
Because only text-like files are allowed, anything visual must come from the caller or from the generation tools at run time. A logo, for example, should be passed as an HTTPS URL in input or as an attachment on each run. If the logo changes, you change the call, and not the package. A batch of file edits is one commit and one version increase, which keeps the history readable when several files change for one reason.
Sources
Related posts
More in Formats
- Cancel a Format run: cancel_effect, no_op and what you still pay
POST cancel on a Format run is idempotent. cancel_effect says canceled or no_op. You pay for generation done before the cancel, and no webhook is sent.
- Format run cap for 25 Nano Banana 2.1 images: $5.00 at 4K
A Format run that makes 25 Nano Banana 2.1 images costs $2.50 at 1K, $3.75 at 2K and $5.00 at 4K. How to set generation_spend_cap_usd and the Format default.
- Format run spend cap: the $400 default, in receipt micros
A Format with no cap set reports 400000000 micros. How the run cap, the $500 maximum, null and 0 behave, and why billable_amount is not the whole bill.
- How long to poll a Format run: use expires_at, not your own timeout
A non-terminal Format run receipt carries expires_at, 90 minutes after created_at or earlier if the run goes silent. Set your poll ceiling from it and back off.
Written by Sume