Resource discovery
Find and manage resources and their loading rules.
Manual for v0.9.5. Stable release: v0.9.5.
Prompts, skills and executable extensions share one filesystem resolver. Each
type's parser owns its format. The resolver owns the safety and precedence
rules. The built-in auto, light and dark appearances work through /theme
without theme files. Named theme files follow the separate, bounded theme
loader.
Locations and precedence#
| Kind | Global | Trusted project | Explicit option |
|---|---|---|---|
| Prompt | ~/.octet/prompts/*.{md,toml} |
.octet/prompts/*.{md,toml} |
--prompt-template <file-or-dir> |
| Skill | Ordered user roots | Ordered project roots | --skill-dir |
| Extension | ~/.octet/extensions/*/extension.toml |
.octet/extensions/*/extension.toml |
--extension-dir |
Roots are visited global, then project, then explicit in option order. An
explicit prompt source can be one .md or .toml file, or a directory. A later
definition with the same name wins, and the shadowed path stays in the
diagnostics. Scans and ordering are deterministic.
A valid package-manager install.json admits an installed bundle's nested
skills/ root. Copying an extension directory in by hand doesn't. Bundle skills
rank below ~/.octet/skills, stay inactive until loaded, and disappear from
discovery once the package is removed.
Workspace resources are ignored without --workspace-trusted. Explicit paths
are your choice for that run.
Extensions add a second boundary. Discovery and workspace trust never launch
code. Installed executable extensions are disabled by default. Full access
(unsafe_host, the default) implicitly trusts the selected, validated source,
so an extension you've enabled needs no extra trust flag. Trust and enablement
are separate, and implicit trust never writes a grant to config. Process startup
still respects --no-process and --no-shell.
--safe-mode removes implicit host authority, so enabled extensions start only
with an explicit grant for the selected source. A grant lets code run as a host
process with your OS permissions, outside the tool-effect broker. Safe mode
isn't an extension sandbox. A project config can't create a persistent host
authority grant. A bare name in persistent trust applies only to the global
extension directory. Project and explicit sources need an exact absolute
name@.../extension.toml grant to persist host authority.
--trust-extension NAME grants it for that run only, and never enables
anything. --extension-dir is itself a one-run grant for that source. Grants
don't transfer between sources, and they permit startup under safe mode. The
extension directory name must match the manifest name, and source,
compatibility, bundle and artifact validation stay mandatory.
If octet can't resolve an absolute home directory, it disables global config and resources with a diagnostic. It never falls back to the invocation directory and treats project files as user-owned.
Skill roots#
Skill discovery goes from lowest to highest precedence:
- User:
~/.agents/skills, then~/.pi/agent/skills, then managed extension skills, then~/.octet/skills. - Trusted project:
.agents/skillsroots from the workspace through the invocation directory, then the invocation directory's.pi/skills, then the workspace's.octet/skills. These need--workspace-trusted. - Explicit:
--skill-dirsources, in command-line order.
A project root that's also a user skill root is scanned only in the user tier.
For example, starting in your home directory keeps ~/.agents/skills and
~/.octet/skills user-installed, with no untrusted-project warning for those
roots. That doesn't trust the workspace: distinct project roots, including
nested .agents/skills and the invocation's .pi/skills, stay gated. Root
symlinks are still rejected.
A later definition replaces an earlier one with the same skill name, and
collisions go in the diagnostics. Discovery never activates a skill. The native
entrypoints are ~/.octet/skills/*/SKILL.md, .octet/skills/*/SKILL.md and
managed ~/.octet/extensions/*/skills/*/SKILL.md. These locations don't promise
full Agent Skills or Pi parser compatibility, or extra symlink support. Those
shapes need their own source contract.
Skill catalog budgets#
The skill catalog the model sees is capped: 1024 bytes per description, 256 descriptors / 256 KiB of payload, and 64 KiB of rendered text. Leaving a skill out of the catalog doesn't deactivate it.
The exact caps and what omission means
Discovery accepts at most 32 KiB of YAML frontmatter per skill and scans at most 4096 entries per root. Those are per-input limits. Across all roots, the retained catalog also has these caps:
- 1024 UTF-8 bytes per description, including an ellipsis when shortened. Only the metadata excerpt is shortened. The source file and instruction body are unchanged, and the full description allocation isn't kept.
- 256 descriptors / 256 KiB of descriptor payload, whichever comes first. Payload counts text fields, encoded paths and JSON-serialized arbitrary metadata, not allocator overhead. Admission follows deterministic root and candidate order. A later definition still replaces an earlier one with the same ID, and if a larger replacement doesn't fit, its predecessor is removed rather than advertised as the winner.
- 64 KiB of rendered model-catalog text, including XML escaping, framing,
paths and any cap notice. Rendering uses ID and path order and stops before
the first entry that doesn't fit. Names, location paths, XML entities and
closing tags are never cut.
disable-model-invocationskills stay excluded.
Description caps and omitted counts appear in discovery diagnostics. Winning
source locations stay indexed, so a known /skill:NAME or /skills load NAME
can still load an omitted skill, with the usual trust, required-tool, symlink
and 256 KiB file limits. An omitted header is parsed on demand, and a changed
skill ID needs rediscovery. Listing and search use the bounded descriptors, not
the full source index. These limits bound retained descriptors and model
context, not total discovery work or RSS: the lightweight source index and
diagnostics still grow with discovered inputs.
Reads and diagnostics#
octet-native resource roots, selected files and directory entrypoints must be regular, non-symlink files. Parser reads use descriptor-bound no-follow opens and fixed byte limits:
| Kind | Maximum parser input |
|---|---|
| Prompt | 512 KiB |
| Skill entrypoint | 256 KiB |
| Extension manifest selected by the product resource resolver | 256 KiB |
Invalid UTF-8, bad names, inaccessible roots, rejected links, oversized files, parser failures and precedence decisions all show up as diagnostics. One broken customization doesn't stop octet starting.
Automatic reload doesn't repeat resource, bootstrap or keybinding problems for each checked component. A successful check clears that component's remembered problem, so a later recurrence shows up. Skipped checks don't clear it. Explicit commands still report their diagnostics, and real work losses are never hidden as duplicate configuration warnings.
Other limits
After discovery, prompt expansion, skill resource reads, extension protocol
messages and session files each have their own narrower limits.
ExtensionManifest::load has a separate 64 KiB default. Product discovery reads
the selected manifest within the 256 KiB bound, then calls
ExtensionManifest::parse.
Reload#
Each discovery pass makes an immutable snapshot. octet builds a complete replacement from it and swaps only after validation, so a running prompt never sees half a reload.
/skills reloadrefreshes prompts and skills./extensions reloadhandshakes replacement processes when enablement and host authority allow startup. Safe mode starts granted sources, not ungranted ones./reloadruns full discovery and rebuilds the active customization.