Skip to content

Skills, agents and commands ​

Three kinds of markdown file change what noeta does without any code: skills (instructions the model loads when a task calls for them), agent files (an agent's system prompt, tools and plugins), and slash commands. All three are in Claude Code's formats, read from noeta's own places. Claude Code plugin directories bring all three at once.

Skills ​

A skill is a directory holding a SKILL.md: YAML frontmatter, then the instructions. The model sees each skill's name and description in a listing and loads the whole file with the Skill tool when it needs it; you can also type /<name> [arguments].

markdown
---
description: Cut a release: bump the version, update the changelog, tag. Use when asked to release or ship a version.
arguments: [version]
allowed-tools: Bash(git *), Edit
---
Release version $version of this project.

The last tag: !`git describe --tags --abbrev=0`

1. …

Save it as ~/.noeta/skills/release/SKILL.md, and the skill is called release: a skill is named by its directory; the frontmatter name is only a display name (noeta/plugins/skills/registry.py).

Where skills are found ​

Managed /etc/noeta/.noeta/skills always You ~/.noeta/skills · ~/.agents/skills always The project, nearest first .noeta/skills · .agents/skills trusted only Additional directories --add-dir · additionalDirectories trusted only Command files .noeta/commands/*.md read as skills Claude Code plugins <plugin>:<skill> plugin dirs Below the working directory apps/web:deploy never shadow first wins looked for, highest precedence first The listing recorded once per task 1% of the context window each description ≤ 1,536 chars over budget: short forms first most used first Loaded when needed Skill(skill, args) or typed by you as /name Skills are looked for again on new input, so one added mid-task is found.
Where the skills plugin looks, highest precedence first; the first skill of a name wins
PlaceRead
the machine's managed directory's .noeta/skills (/etc/noeta, /Library/Application Support/Noeta on macOS)always
~/.noeta/skills/<name>/SKILL.mdalways
~/.agents/skills/<name>/SKILL.md, the directory coding agents share (under your home directory, not moved by $NOETA_HOME)always
.noeta/skills/ and .agents/skills/ in the working directory and each directory above it up to the repository's root (nearest first; .noeta before .agents in one directory)trusted projects
the same in each additional directory (--add-dir, additionalDirectories)trusted projects
the managed directory's .noeta/commands/, ~/.noeta/commands/, then the project's and additional directories' .noeta/commands/ (trusted projects)*.md files, as skills (below)
a Claude Code plugin's skills/named <plugin>:<skill>
.noeta/skills and .agents/skills below the working directory, once a file tool touches a file theretrusted projects; never shadowing: one whose name is taken is named <dir>:<skill> (apps/web:deploy)

The first skill found under a name wins, as in Claude Code, and the order is deterministic, so the same tree always gives the same listing. A skill directory more than one level deep holds no skill. Claude Code's .claude/skills is never read. A project that is not trusted (noeta trust) has its skill directories skipped, with a notice. Skills are looked for again whenever new input is taken and before each model call when a SKILL.md changed, so a skill you add mid-task is found at once.

Frontmatter ​

KeyWhat it does
descriptionWhat the listing shows; without one, the body's first line (up to 100 characters)
when_to_useFollows the description in the listing, after a dash
nameA display name shown beside the skill's name
argumentsNames for the words after /<name>: $version is the first, and so on
allowed-toolsTools the skill's work may use without asking (pre-approved while it is active)
disable-model-invocation: trueNot in the listing: only you can run it, by typing /<name>
user-invocable: falseNot offered as /<name>; the model may still load it
pathsGlobs: the skill is listed only once a file tool has touched a matching file
context: forkRuns in a sub-agent (agent, default general-purpose) instead of the conversation; disallowed-tools takes tools from that agent
model, effortThe rest of the turn that loads the skill runs with this model and effort
versionKept as metadata

In the body, $ARGUMENTS is the whole argument string, $0, $1 (or $ARGUMENTS[0]) the shell-quoted words, $<name> a named argument, \$ a literal dollar; arguments no placeholder took follow the body on an ARGUMENTS: line (noeta/toolkit/arguments.py). ${NOETA_SKILL_DIR} (or ${CLAUDE_SKILL_DIR}) is the skill's directory, and the loaded text starts with a "Base directory for this skill" line so the model can read the files beside it. A !`command` (after a line start or a space), or a fenced block opened with ```!, runs when the skill loads and is replaced by the command's output. Each command goes through the task's permission checks as a Bash call; one that would be refused, or would need your answer, stops the skill from loading, since there is nobody to ask at that moment (noeta/toolkit/inline_commands.py).

The listing and its budget ​

The Skill tool's own description never changes; the skills reach the model as a listing recorded once per task, as Claude Code does (noeta/plugins/skills/listing.py). A skill added later, or whose description changed, is listed again under the same header; removals are not announced.

The listing gets 1% of the model's context window (in characters: the window times the model's characters per token). Each description is cut at 1,536 characters. Over budget, every skill first gets a short form (its first sentence, at most 24 tokens), then, as budget allows, its full description, in order of use (skills used most across the store's tasks first), then place, then name. A name is never dropped. To change the budget:

SettingWhere
skillListingBudgetFraction (0–1), skillListingMaxDescCharsa settings file (Claude Code's keys)
NOETA_SLASH_COMMAND_TOOL_CHAR_BUDGETthe budget in characters, for every task

Agent files ​

An agent is a markdown file: YAML frontmatter saying what it is, and its system prompt as the body (noeta/agents/agent_files.py). It is Claude Code's format plus two fields of noeta's, plugins and one_shot.

markdown
---
name: reviewer
description: Reviews a diff for bugs. Use after making changes, before committing.
model: sonnet                 # inherit, an alias, or a model id
tools: Read, Bash             # offer only these ("*": all)
disallowedTools: Edit, Write
permissionMode: default
maxTurns: 40
effort: high
---
You review code changes. Read the diff with `git diff`, …
FieldWhat it does
name, descriptionIts name, and what the model reads when choosing a sub-agent
modelinherit (the caller's model), an alias (sonnet, opus, haiku, fable) or an id
tools, disallowedToolsOffer only these tools; never offer these (a rule like Bash(npm:*) counts as its tool)
permissionModeThe mode it runs in
maxTurnsModel calls per turn
effortIts effort
omitClaudeMd: trueShown only the managed instruction files
identityThe one-line identity block that opens its system prompt
pluginsIts plugins, in order: names, or name: {arguments} (noeta's)
one_shot: trueEnd with the first turn's answer (noeta's)
skillsSkills loaded when it starts
mcpServersMCP servers for it: inline definitions, or names configured elsewhere
hooksHooks while it runs (its Stop hooks become SubagentStop when it runs as a sub-agent)
memory: user|project|localIts own memory directory (memory)
isolation: worktreeAs a sub-agent, runs in a git worktree of its own
initialPrompt, autoCompactWindow, criticalSystemReminder_EXPERIMENTALas in Claude Code

A field noeta does not act on (cacheTtl, observer, …) is logged once. A file with no plugins (a plain Claude Code agent file) gets the default set: permissions, plan mode, budget, hooks, shell, web, MCP, files, skills, instructions, environment, sub-agents, compaction and a few more (noeta/agents/__init__.py DEFAULT_PLUGINS). Every agent also runs tool_search and structured_output.

Where agent files are found ​

PlaceNamed
the built-ins, noeta/agents/files/*.mdmain, Explore, general-purpose, Plan
a Claude Code plugin's agents/**/*.md<plugin>:<agent>
~/.noeta/agents/*.mdby name
a trusted project's .noeta/agents/*.mdby name
--agents '{"name": {"description": …, "prompt": …}}' (headless)by key

A later file replaces an earlier one of the same name, in that order, so your ~/.noeta/agents/Explore.md replaces the built-in Explore. /agents in the terminal UI lists them; /reload-plugins reads them again.

The built-in agents:

AgentWhat it is
mainThe agent you talk to: every plugin, the main system prompt
general-purposeA sub-agent for research and multi-step work, with the file and shell tools
ExploreA read-only search sub-agent (Read only among the file tools; no edits, no sub-agents of its own)
PlanA read-only sub-agent that designs an implementation plan

The model can also start subagent_type: "fork", a copy of itself that inherits the whole conversation. Running sub-agents, in the background and otherwise: sub-agents.

To start the terminal UI or -p with another agent than main: noeta --agent reviewer, or "agent": "reviewer" in a settings file.

Adding plugins without copying a file ​

config.toml adds plugins to an agent by name, after the file's own; "*" is every agent:

toml
[agents.main]
add_plugins = ["repetition_guard", {my_plugin = {level = 2}}]

[agents."*"]
add_plugins = ["run_tests"]

[plugins.web]
enabled = false          # off for every agent

Of the plugins the built-in agents name, memory, mcp and repetition_guard stay off until a host sets them; the noeta command turns memory and MCP on. Writing a plugin: Write a plugin.

Slash commands ​

A slash command is something you type as /<name> [arguments]. Besides the front end's own (terminal UI), they come from the agent's plugins, so the same commands work in the terminal UI, the web app, editors and headless runs.

Markdown commands. ~/.noeta/commands/<name>.md and a trusted project's .noeta/commands/<name>.md are Claude Code's command files. noeta reads them as skills (as Claude Code now does): you can type /<name>, and the model can load them with Skill. A file in a subdirectory is named with its path (.noeta/commands/git/fixup.md is /git:fixup).

markdown
---
description: Make a fixup commit for the last change to a file
argument-hint: <path>
allowed-tools: Bash(git add *), Bash(git commit *)
---
Stage $ARGUMENTS and make a `git commit --fixup` for the last commit that touched it.

Claude Code plugins' commands (commands/**/*.md in a plugin directory) are typed through the markdown_commands plugin (noeta/plugins/markdown_commands.py), named <plugin>:<name>; the model can load them too. Typing one sends the command; the task adds its body with the arguments filled in, runs its !`…` lines through the permission checks, and pre-approves the tools its allowed-tools names from then on.

The same plugin offers two prompt commands of its own: /init (write a NOETA.md for this project, or improve the NOETA.md or AGENTS.md there) and /review [PR | branch | paths] (review changes for defects, changing no files).

Other plugins' commands: /compact, /plan, /loop, /mcp, /hooks, and an MCP server's prompts as /mcp__<server>__<prompt>. A plugin adds its own with commands() and run_command() (Extension interface).

Claude Code plugin directories ​

A Claude Code plugin directory (.claude-plugin/plugin.json, skills/, agents/, commands/, hooks/hooks.json, .mcp.json) put in ~/.noeta/plugins/, or a trusted project's .noeta/plugins/, loads through the plugins that already read those formats (noeta/cli/claude_plugins.py):

PartLoaded as
skills/skills, named <plugin>:<skill>
agents/**/*.mdagent files, named <plugin>:<agent>
commands/**/*.mdtyped commands and skills, named <plugin>:<command>
hooks/hooks.jsonhooks
.mcp.jsonMCP servers (never from a project's plugin: you are told to copy them into .noeta/mcp.json)
settings.json agentthe agent front ends start with, below your own settings

${CLAUDE_PLUGIN_ROOT} and ${CLAUDE_PLUGIN_DATA} (~/.noeta/plugin-data/<name>) are filled in everywhere, and the manifest's userConfig values as Claude Code fills them. Monitors, bin/, LSP servers, themes and output styles are not loaded. Install one pinned to a commit:

bash
noeta plugin add https://github.com/you/your-plugin@<full commit: 40 hex digits, 64 in a SHA-256 repository>
noeta plugin add --marketplace ./team-marketplace formatter     # from a marketplace.json
noeta plugins                                                    # what is loaded, and from where

Installing runs nothing from the plugin. More on installing and configuring them: Write a plugin.