@package-system

Instructions, rules, agents, docs, and team

The markdown contribution categories and how each reaches the system prompt.

Beyond tools and skills, a package contributes plain markdown that shapes agent behavior. Five first-class categories become typed arrays on the package definition — skills, instructions, rules, agents, docs — plus team members. Each markdown contribution lives in its category folder, needs a frontmatter name (or id) to be discovered, and carries its category from the folder, never from frontmatter (see the directory contract).

Category cheat-sheet

FolderCategoryReaches the model asUse for
rules/*.mdruleAlways-on system-prompt block, near the topHard constraints the agent must always obey
instructions/*.mdinstructionSystem-prompt block, grouped with rulesHow-to guidance and workflows
docs/*.mddocsListed in the package overview (title + description); read on demand — not injected by defaultBackground and reference material
skills/<name>/SKILL.mdskillAdvertised in the package overview; body rendered on activationProcedural capability bundles
agents/*.mdagentSpawnable delegate personaSub-agent identities

Workflow templates (workflows/*.json)

A template's optional execution policy can declare a model id, reasoning effort, an exact catalog-declared base or extended context override, and fast mode. Template and persisted contract values are null-free: omission means inherit from the target agent. Clearing is a runtime update operation, not an authored template value, and explicit false means fast mode is off. Provider capability validation is performed by the consuming workflow runtime rather than duplicated in the package kernel.

Packages can also ship workflow templates — blueprints for scheduled or recurring agent runs. These are deliberately not a markdown category: workflows/*.json becomes a parallel typed array (PackageWorkflow[]) like tools, is validated strictly at load (an invalid template fails the package load), and is never injected into the system prompt. The model reaches templates only through the workflow routes, with the manage-workflows skill's template scripts (list, install, upgrade); users reach them through the same routes and the Calendar's template browser.

A template declares its id (from the filename), a title and description, a defaultInstructionTemplate, and optional defaultTriggers. All four trigger kinds are authorable — manual, schedule (a cron expression or a once timestamp, both bounded by endAt, cron additionally by maxRuns), webhook, and message — while the engine-runtime fields inside a trigger (fire counters, next-fire time, webhook token material) are rejected at validation. An optional inputs map describes its {{PLACEHOLDER}} parameters using the GitHub-Actions workflow_dispatch.inputs field names (description, required, type string/choice/boolean, default, options); three placeholder names are engine-owned and rejected as input keys — WORKFLOW_DIR, WORKFLOW_STATE_URI, and FIRE_TIME, all substituted at fire time. An optional requires.features visibility gate carries the same semantics as requiredFeatures on markdown contributions.

The rest of the shape is presentation and per-entry defaults: icon, color and group for the calendar and the template catalog; teamMemberSlug names a packaged team member's agent (validated, but no runtime reads it yet); defaultStateMode (fresh starts each run clean, continue keeps the run conversation); a defaultExecutionPolicy (maxConcurrent, maxRuntimeMs, and optional modelId, reasoningEffort, contextWindowOverride, fastMode); a defaultSessionSetup carrying the run's goal and loop bounds; and requiredCredentials, the credential-catalog ids the instruction's skills and tools will need.

A template may also declare a delivery intent (announce / webhook / none) and the channelKinds it expects to deliver to: an announce template installs with announce delivery already enabled on the entry, and the install surfaces show the channel hint — actual routing still requires an explicit channel binding created by the user. Cron defaults always carry the UTC timezone (template inputs never reach triggers, so a shipped cron must not depend on install-time locale) — say so in the description and let users edit the schedule after install.

Installing a template validates the supplied inputs, substitutes them into the instruction, and creates a draft workflow owned by the installing user — every later fire runs with that user's current permissions. Disabling the source package suspends installed workflows at their next fire instead of running them; re-enabling does not auto-resume. If your package ships templates, remember to add workflows to the package.json#files whitelist.

A template may carry an optional revision (a positive integer; omitting it means revision 1). Because installing copies the instruction into the workflow rather than live-linking it, bumping a shipped template's revision is how you signal that already-installed copies are stale: the platform pauses an out-of-date active copy (surfacing an "upgrade required" reason) rather than silently rewriting a user's installed instruction. Someone allowed to edit that workflow then upgrades it in place — it keeps its identity, run history and state — and resumes it after reviewing the new text.

Declared sources (sources[])

Like workflow templates, declared sources are a parallel typed array on the package definition (sources[]), not a markdown category and never injected into the prompt. Each entry declares a concrete filesystem source instance — of a connector kind already registered via connectors[] — that the platform seeds into every project (seed: "auto") or offers for on-demand add (seed: "discoverable"). Declarations are trust-gated at load, and the declaring package becomes the source's origin attribution. Full reference: Connectors → Declaring sources.

Prompt-injected categories

Rules and instructions are injected into the system prompt for every turn, each wrapped in a <package_file> block that carries its category, id, owning package and title:

<package_file category="rule" id="mutation-safety" package="brain-core" title="Mutation safety">
...the file body, without its frontmatter...
</package_file>

The frontmatter is dropped when every key in it is one the platform renders itself (id, name, title, description, activation, requiredFeatures, defaultEnabled, overwrite). Any other key keeps the whole file, frontmatter included — an imported rule's scope (paths, applyTo, globs) still reaches the model that way. A file the prompt already carries is named in the package overview without repeating its description.

They render near the top of the prompt (primacy). Within each group, files sort by category priority and path; each file's content is capped at injection time by the packageFileMaxChars platform setting (default 8,000 characters, admin-tunable). Flat {{conversationId}}, {{agentId}}, {{projectId}}, and {{userId}} placeholders substitute at injection; dotted forms such as {{user.name}} ship literally and should not be used.

docs/*.md are not injected. They are listed in the package overview by title and description, and the agent reads them on demand — the same lazy model as a skill body. A built-in package's doc is read through the agent-core inspection skill (files.sh content <package> <category> <id>), which serves only an active file the caller's own catalog lists; a project-installed or source package's doc is read with fs_read on its URI. (An author can force a single doc into the prompt with frontmatter activation.pinned or activation.target: "prompt-context", but this is rare and discouraged: put behavioral content in rule/instruction and leave reference in plain docs.)

Because injected files cost tokens on every turn, keep rules and instructions tight, push long reference into docs (read on demand), and put procedural detail into a skill body — a skill renders only on activation.

Rules are a first-party privilege

For any package below first-party trust, discovery downgrades rules/ contributions to docs. A project-installed package can ship reference material, but it cannot inject always-on behavioral constraints into the system prompt.

Agents — delegate personas

An agents/*.md file defines a persona the platform's delegate tool can spawn as a sub-agent. The file body becomes the child agent's system prompt; frontmatter name, allowed-tools, and model are honored when the run is created — and on a persona an explicitly empty allowed-tools: [] is honored too, as a child with no tools, while omitting the field inherits the caller's own set. On a persona the list is a ceiling: a delegate call naming its own tools is intersected with it and can only narrow, the dropped names are reported back in the result, and a call asking for none of them is refused. The delegate tool resolves a requested agent by id or name from the first-class agent array, falling back to skill-forks — skills whose frontmatter declares context: fork register in the agent category and resolve the same way.

---
name: reviewer
description: Reviews a change set against the project conventions.
allowed-tools: [fs_read, fs_search]
---

You are a meticulous code reviewer. Inspect the files you are pointed at...

The child run inherits the parent's package enablement and the caller's real identity and grants — a delegate never escalates beyond what the calling user could do.

Docs

docs/*.md is the category for material the agent should be able to consult without obeying it as a constraint: API references, background, lookup tables. Docs are not auto-injected into the prompt: they are listed in the package overview by title and description and read on demand, exactly like a skill body. This category is also the landing spot for anything trust-sanitized out of rules/.

Team members

team/<slug>/ ships a ready-made agent character — package-provided base configuration for the agent-creation flow:

team/
  search-agent/
    member.json        # slug, name, role, description, config, permissions, appearance
    identity/          # *.md identity files injected for this member
    files/             # *.md additional member files

member.json carries the create-agent shape:

{
  "slug": "search-agent",
  "name": "Search",
  "role": "assistant",
  "description": "What this coworker is for, and when to pick it.",
  "config": {
    "settings": {
      "maxSteps": 15,
      "defaultModelId": "provider/model-id",
      "guardProfile": "balanced"
    }
  },
  "permissions": { "sources": ["brain"], "features": ["core.agents"] },
  "appearance": { "icon": "search", "color": "#3b82f6" }
}

Four rules that are easy to get wrong:

  • description is the field that reaches a model. A member may also carry descriptionForModel, but nothing reads a member's copy — only the package-level descriptionForModel is advertised. Put the "when to pick this coworker" sentence in description.
  • Pin a model and a guard posture inside config.settings, as defaultModelId and guardProfile. There is no top-level model, icon, or color key — appearance nests under appearance.
  • Identity placeholders substitute once, at provisioning. When an agent is created from the member, each identity/*.md and files/*.md is copied into the agent's own data directory with a fixed eight-key substitution: {{agentId}}, {{agentName}}, {{createdAt}}, {{packageId}}, {{memberSlug}}, {{role}}, {{projectId}}, {{userId}}. There is no per-turn re-substitution, and {{conversationId}} is not in the set — write it and it ships to the model literally. Dotted forms such as {{user.name}} ship literally everywhere.
  • Identity-file frontmatter is stripped, not parsed. activation, pinned, and priority on an identity file do nothing; injection order is fixed by filename, so name the files in the order you want them read.

A team directory without a member.json is skipped.

Visibility

Every category obeys the same two gates, deny-by-default:

  • Package state — a disabled package's contributions are not injected, not advertised, and not listed.
  • Caller grants — a contribution may declare requiredFeatures: [a, b] in frontmatter (flat flow array). A caller missing any listed feature never sees it: not in the prompt, not in the package overview, not in the files catalog. Hidden means hidden — gated contributions are never rendered as locked or off, so non-holders cannot infer they exist.

The predicate and grant model are described in Features and access.

Within those gates, every file contribution of every package is also individually toggleable at two scopes: agent scope in the packages editor, and conversation scope in the composer's package selector, where every package row expands into per-file rows (opt-in files badged). An agent-level per-file off is final — a conversation cannot re-enable it. The full precedence chain is described with the source-package defaults on Source packages.

Source-contributed packages

A synced filesystem source can contribute the same five categories too — no package.json required. A mounted repository's .claude/ or .cursor/ folder, a directory of skills/ and rules/, or a free-standing SKILL.md folder groups into a source package that behaves like any other package, with deliberate defaults (source rules and identity files are opt-in, docs are never auto-injected) and per-file toggles at both agent and conversation scope. The full story — recognized layouts, grouping rules, defaults, skill activation, and the security model — is on Source packages.

On this page