Agotalk Role Package — Creator Guide (v0.3)
This is the public creator guide for creating an Agotalk role package. The stable package file contract lives at /docs/role-package.md. Audience: AI agents and developers. Read this whole file before generating anything.
A role package is a plain directory of files, shipped as a plain zip. The package truth is role.md plus the file tree. agotalk.role.toml is the machine contract that adds identity, preview metadata, and (for applications) a launchable entry. There is no other manifest. Do not invent one.
1. Three capabilities — pick exactly one path
Importable, launchable, and publishable are three different contracts. Decide what you are building first:
- Path A — minimal local candidate (importable only).
A single directory with a valid role.md and NO agotalk.role.toml. Agotalk imports it into the local Role Library as a candidate. Not launchable. Not publishable to the website (publishing requires the machine contract).
- Path B — launchable application (importable + launchable + publishable).
kind = "application" with an [entry] that is a complete, valid static_browser entry. Applications get a Launch button.
- Path C — conversational role (importable + publishable, no Launch).
kind = "role" with NO [entry] section at all. role.md is the sole behavior source: the role talks, it does not launch. The publisher accepts it exactly like an application. In the Role Library it appears as a normal selectable candidate without a Launch button.
Hard rule behind the paths, dispatched by kind:
kind = "application"—[entry]is mandatory and only
entry.kind = "static_browser" passes the contract parser. Unknown entry kinds fail loudly with ROLE_ENTRY_KIND_UNSUPPORTED.
kind = "role"—[entry]is forbidden. Declaring any[entry]fails
with ROLE_CONTRACT_FIELD_INVALID; a missing role.md fails with ROLE_BEHAVIOR_FILE_MISSING. There is no system_prompt entry kind and there never was a working one — the behavior contract is role.md itself.
Publishable examples: words-john, teacher-tori, visual-media-assistant Import-only examples: any Path A directory (role.md without agotalk.role.toml)
The live published examples are words-john (https://roles.agotalk.com/roles/words-john), a Path B application, and teacher-tori (https://roles.agotalk.com/roles/teacher-tori), a Path C conversational role. Their official sources live in the separate agotalk-roles repository, not in the Agotalk app repository.
2. Package layout
<role-id>/
role.md # REQUIRED. Role intro, boundaries, how to start. Import entry.
agotalk.role.toml # Path B/C: machine contract (identity, preview; entry for B only)
avatar.png # optional role avatar at the package root (recommended 512x512 PNG)
intro.html # optional rich presentation page (static HTML only)
skills/ # optional agent instructions (*.md). No software here.
contents/ # optional real software content: source, pages, locks
assets/ # optional presentation media (covers, screenshots)
Rules:
<role-id>is lowercasea-z0-9words joined by single hyphens
(example: words-john). The directory name IS the role id.
skills/*.mdonly explain how to use or modifycontents/; they never
contain the software itself.
intro.htmlis presentation only. It never replacesrole.mdand never
declares runtime dependencies.
- Extra content directories are allowed when they serve the role (example:
teacher-tori ships curriculum under resources/). Keep everything inside the package directory.
- The role avatar is a single
avatar.pngat the package root (not under
assets/), recommended 512×512 PNG. If omitted the role shows the default Agotalk avatar. Do NOT declare an avatar: field in role.md front matter — that field is retired (tk2332) and the import gate rejects any package still carrying it with ROLE_PACKAGE_LEGACY_AVATAR_FIELD.
3. role.md (required)
Front matter with title and description, then the role narrative: who the role is, what it does, its boundaries, and how a session should start. The Role Library shows title and summary from this file. For Path C roles this file IS the entire behavior contract — write it with care.
The only front matter keys consumed are title and description. The avatar: key is retired (tk2332): the avatar is the package-root avatar.png, never a front matter value. A package whose role.md front matter still contains avatar: is rejected at import with ROLE_PACKAGE_LEGACY_AVATAR_FIELD — delete the line and place avatar.png at the package root instead.
Front matter field status (the parser is the contract):
| Key | Status | Notes | |---|---|---| | title | consumed | Falls back to the role id (directory name) if absent/empty. | | description | consumed | Falls back to "" if absent/empty. | | id | ignored as identity | Role identity is ALWAYS the directory name (path.basename); a front matter id is tolerated but never overrides it. | | avatar | retired (tk2332) | Hard-rejected at import (ROLE_PACKAGE_LEGACY_AVATAR_FIELD); installed roles only log. Use package-root avatar.png instead. | | any other key | tolerated, ignored | Unknown keys do not error; they are simply not read. Do not rely on them carrying meaning. |
4. agotalk.role.toml (machine contract)
Path B — launchable application:
schema_version = 1 # fixed
id = "words-john" # must equal the top-level directory name
version = "0.1.0" # SemVer string
title = "Words John"
summary = "Typing word game bundled as role package content."
kind = "application" # dispatches the entry contract
license = "free" # v0.2: "free"
min_app_version = "0.1.57" # optional: minimum Agotalk App version
[entry] # mandatory for kind = "application"
kind = "static_browser" # the only kind that parses and publishes today
target = "contents/word-pop-game/index.html" # relative, must stay inside the package
address_bar = "hidden" # "visible" | "hidden"
[preview]
intro_html = "intro.html"
cover_image = "assets/screenshots/word-pop-game-preview.png"
screenshots = ["assets/screenshots/word-pop-game-preview.png"]
[state]
remembers_progress = false # declare true only if the app really saves progress
[environment]
manager = "agotalk" # fixed
dependency_mode = "none" # static content needs nothing else
Path C — conversational role (note: NO [entry] section):
schema_version = 1
id = "teacher-tori"
version = "0.1.0"
title = "Tori"
summary = "Tori — a warm but exacting English teacher."
kind = "role" # conversational: role.md is the behavior source
license = "free"
min_app_version = "0.1.57" # optional: minimum Agotalk App version
[preview]
intro_html = "intro.html"
[state]
remembers_progress = true
[environment]
manager = "agotalk"
dependency_mode = "none"
Notes:
- The entry contract is dispatched by
kind: applications must declare a
complete [entry]; conversational roles must not declare one at all.
min_app_version("x.y.z") is optional publish metadata. When present it
feeds the catalog; the publisher can also receive an explicit --min-app-version. One of the two must exist to publish — the publisher never silently substitutes its own version.
[preview]is consumed by the Agotalk App import preview, and the publisher
also projects avatar.png, preview.cover_image, and preview.screenshots into the website presentation assets (converted to WebP and served from the catalog) — package images DO drive the website. Recommended specs (not enforced by the parser): - avatar.png at the package root — 512×512, 1:1, PNG. - cover_image — 1280×720, 16:9, PNG. - screenshots — 1 to 3 images, 1280×720, 16:9, PNG. - 16:9 at 1280×720 matches og:image / Twitter card / Steam capsule conventions; authors can drop a 16:9 capture without re-cropping. - Keep each image under ~1 MB. - Avoid JPEG for screenshots (lossy edges blur text) and avoid SVG for screenshots (use SVG only for logos/icons). GIF is accepted but not recommended for detailed captures. - Keep source images PNG; the publisher converts website presentation copies to WebP automatically. Authors never pre-convert to WebP.
[i18n."<locale>"](optional) localizes the displaytitle/summaryper
locale — e.g. [i18n."zh-CN"] with exactly title and summary keys (same length limits as the top-level fields). Locale keys look like en or zh-CN; at most 8 locales. Top-level title/summary are the canonical fallback — write them in the role's primary language. The catalog and the website language pages pick the locale entry when present.
static_browseris the ONLY entry kind that exists today. Any other value
(including anything you may have seen in older drafts) fails loudly with ROLE_ENTRY_KIND_UNSUPPORTED. Do not experiment with entry kinds that are not in this guide — the parser is the contract.
- All referenced paths (
entry.target,preview.*) are relative to the
package root and must stay inside it.
schema_versionmust be exactly1andlicenseis currently locked to
"free". Any other value fails with ROLE_CONTRACT_FIELD_INVALID.
environment.managermust be exactly"agotalk"and
environment.dependency_mode must be exactly "none". Any entry kind that would imply a dev server, dependency install, or local backend is rejected by the parser — today only self-contained static apps ship as role packages.
5. Authoring app content and role-specific skills
This section is for Path B packages (and Path C roles that ship reference content). It describes what the app running inside Agotalk can and cannot do, and how to write the role-specific Markdown under skills/.
What the app environment can and cannot do
A static_browser app opens inside Agotalk's bundled browser view. That view is a sandboxed web page: it renders HTML/CSS/JS from files inside the package, with no access to the local machine. Specifically:
- The page has no Node/Electron bridge and no shell access. It
cannot spawn processes, read arbitrary files, run installed tools, or start a backend / dev server.
- The page cannot reach Agotalk's bundled runtime tools (node, python,
tmux, git, ffmpeg, mise, etc.). Those tools serve the agent's workspace shell, which is a separate channel from the role-package app.
- The page may use ordinary browser APIs:
localStorage,IndexedDB,
fetch of package-relative resources, canvas, WebGL, Web Workers, service workers, FileReader, drag-and-drop, clipboard, and so on.
- The page runs fully offline at launch. Do not fetch scripts, styles,
fonts, templates, or data from a CDN or any network endpoint when the app starts — bundle everything into the package.
If your application needs a local backend, a dev server, or a dependency install step to run, it cannot ship as a role-package app today. Convert it to a self-contained static build (vendored libraries, build output only) before packaging.
Putting content into contents/
contents/ holds the runnable artifact of your app — the files Agotalk's browser view will load. There is no install step at launch.
<role-id>/
contents/
<app>/
index.html # entry.target points here
app.js # built or hand-written; vendored, not installed
style.css
vendor/ # third-party JS/CSS copied in at a pinned version
assets/ # app-local media (icons, fonts, templates)
Rules:
entry.targetpoints at theindex.htmlinsidecontents/<app>/.- Ship the built output, not the toolchain. If you build from TS/JSX or
a bundler, the compiled bundle is what goes under contents/<app>/; source and build instructions stay in a separate folder or repo. The package must never require npm install / pnpm install / pip install at launch.
- Third-party libraries must be vendored into
contents/<app>/vendor/at
the exact version you tested. Record the pinned versions (a comment in index.html or a note under skills/) so the package stays auditable.
- If the app persists user data via the browser APIs above, declare
[state] remembers_progress = true only if that data actually survives a reload; otherwise leave it false.
What "Agotalk's bundled runtime" means here
Agotalk ships a curated, version-locked toolchain (node, python, pnpm, mise, tmux, git, ImageMagick, ffmpeg, rg, fd, jq, sqlite, and more) that the agent can call from its workspace shell to do real work on the user's machine. That is a powerful capability — but it belongs to the agent channel, not to the role-package app.
- A Path B/C role's
skills/*.mdcan instruct the agent to use those tools
to maintain, regenerate, or extend the app's contents/ (for example, "rebuild the bundle with pnpm build", "generate sprites with ImageMagick"). The agent runs these in its workspace shell.
- The app's own page (what the Launch button opens) cannot call them. Keep
these two channels separate in your design: the agent maintains the artifact, the browser view runs it.
Writing role-specific skills
skills/*.md are Markdown instructions that tell the agent how to use or modify the contents/ shipped with this role. They are NOT software. Put one Markdown file per distinct job, named after the job.
<role-id>/
skills/
<job-name>.md # one file per job; e.g. rebuild-bundle.md, export-data.md
Each file should state: the job, the exact files or UI it touches, the step sequence (including any bundled tools the agent should call from its workspace shell), and how to verify it worked. Keep them short and concrete — they are read by an agent at session time.
Hard rule (repeated from §2): skills/ holds only Markdown. Any executable, script, stylesheet, image, or binary belongs in contents/ or assets/, never in skills/.
Hard rule (repeated from §2): skills/ holds only Markdown. Any executable, script, stylesheet, image, or binary belongs in contents/ or assets/, never in skills/.
6. What publishing consumes
The official publisher runs the full contract parse dispatched by kind (Path B and Path C both pass; Path A has no contract file and cannot publish), then the catalog and website use: id, version, title, summary, min_app_version (from the manifest or explicit publisher input), plus the computed zip sha256 and sizes. Website preview media is curated on the site side. Publication itself happens through the official publisher pipeline; this guide only defines the package you hand over.
7. Transport zip
words-john-0.1.0.zip
words-john/
role.md
agotalk.role.toml
avatar.png
intro.html
skills/
contents/
assets/
Rules:
- The zip contains exactly one single top-level directory named
<role-id>. - Zip name convention:
<role-id>-<version>.zip. - Plain zip, regular files only: no symlinks, no absolute paths, no
..
entries, no .DS_Store.
- The zip is a transport container, not a second manifest.
Import behavior you must expect: Agotalk unpacks the zip into the local Role Library (roles-lib) as a candidate, validates role.md, and shows the candidate. Importing an id that already exists is rejected with ROLE_IMPORT_DUPLICATE — versions never silently overwrite. A candidate never becomes the active workspace role without explicit user action.
8. Hard boundaries
- The user's machine is never a dependency source. Only the Agotalk bundled
runtime, this contract, and files locked inside contents/ may be assumed.
- **Secrets, tokens and API keys must never be put into a package you intend
to publish.** A published package is public — anything inside it is exposed. If you are building a package strictly for your own local use and you choose to embed your own keys, that is your call and your risk; but such a package must not be published through the official pipeline. The official publisher does not scan for secrets, so the discipline is yours.
- Never rely on network calls at launch time for a
static_browserapp. - Never auto-activate the role or instruct Agotalk to bypass user confirmation.
- When a fact you need is missing (id, version, entry target), stop and say so
loudly. Do not guess silently.
9. Generation instruction (hand this to an agent)
Create an Agotalk role package.
1. Read https://roles.agotalk.com/role-package-creator.md fully first.
2. Pick the capability path: launchable web app for the website -> Path B
(kind = "application" with a static_browser [entry]); conversational role
for the website -> Path C (kind = "role", role.md as behavior, NO [entry]);
local-only experiment -> Path A (role.md, NO agotalk.role.toml).
3. Choose <role-id> (lowercase a-z0-9 and hyphens) and create the directory <role-id>/.
4. Write role.md: front matter (title, description), then the role narrative,
boundaries, and session start guidance. For Path C this file is the whole
behavior contract.
5. If the role ships an app or content: put real files under contents/,
agent how-to notes under skills/, presentation media under assets/.
6. Path B/C: add agotalk.role.toml exactly as specified above. Path B needs a
complete [entry] with an existing HTML target inside the package; Path C
must not contain any [entry] section.
7. Zip as <role-id>-<version>.zip with the single top-level directory <role-id>/.
8. Run the self-check below. Fix every failure before delivering. If a required
fact is unknown, report it instead of inventing it.
10. Self-check before delivery
- [ ] Zip holds exactly one top-level directory; its name equals
idin
agotalk.role.toml (when present).
- [ ]
<role-id>/role.mdexists and carries title + description front matter. - [ ]
role.mdfront matter does NOT contain anavatar:key (retired;
tk2332). The avatar, if any, is a package-root avatar.png (recommended 512x512 PNG). An avatar: line inside the role narrative body is fine; only the front matter block is gated.
- [ ] Path A packages have NO
agotalk.role.toml. Path B packages have a
complete [entry] with kind = "static_browser" and an existing .html target inside the package. Path C packages declare kind = "role" and contain NO [entry] section at all.
- [ ]
schema_versionis exactly1,licenseis exactly"free",
environment.manager is exactly "agotalk", and environment.dependency_mode is exactly "none". These four fields are fixed today; any other value fails the contract.
- [ ] Every path referenced by
agotalk.role.tomlexists inside the package
(entry.target, intro_html, cover_image, every screenshot).
- [ ] If you provide preview media, follow the recommended specs: avatar
512×512 1:1 PNG, cover + screenshots 1280×720 16:9 PNG, each image under ~1 MB. If the website needs WebP, convert curated website media in the website release chain; the role package source contract stays PNG. (Not enforced by the parser.)
- [ ]
min_app_version(when present) is a plainx.y.zstring. - [ ] No symlinks, no absolute paths, no
.., no.DS_Store. - [ ] If you plan to publish: no secrets, tokens or API keys anywhere in the
package. Local-only packages are your own risk but must not be published.
- [ ]
skills/contains only Markdown instructions; software lives incontents/. - [ ] Stable failure codes you may see and must not paper over:
ROLE_IMPORT_ROLE_MD_MISSING, ROLE_IMPORT_DUPLICATE, ROLE_PACKAGE_LEGACY_AVATAR_FIELD, ROLE_CONTRACT_MISSING, ROLE_CONTRACT_INVALID, ROLE_CONTRACT_FIELD_MISSING, ROLE_CONTRACT_FIELD_INVALID, ROLE_BEHAVIOR_FILE_MISSING, ROLE_ID_DIR_MISMATCH, ROLE_ENTRY_KIND_UNSUPPORTED, ROLE_ENTRY_ADDRESS_BAR_INVALID, ROLE_ENTRY_TARGET_NOT_FOUND, ROLE_ENTRY_TARGET_NOT_FILE, ROLE_ENTRY_TARGET_OUTSIDE_PACKAGE, ROLE_ENVIRONMENT_INVALID, ROLE_PREVIEW_INVALID, ROLE_PREVIEW_NOT_FOUND, ROLE_PREVIEW_NOT_FILE, ROLE_PREVIEW_OUTSIDE_PACKAGE, ROLE_STATE_REMEMBERS_PROGRESS_INVALID, ROLE_IMPORT_ZIP_TOP_LEVEL_INVALID, ROLE_IMPORT_ZIP_ENTRY_INVALID, ROLE_KIND_NOT_LAUNCHABLE.