Agent profiles: installable lines of work — "el perfil", "perfiles disponibles", "instalá un perfil" — secretary, project manager and others. Load when the user wants to install, activate, configure, diagnose or remove one, or asks why the agent behaves the way it does. Triggers: 'install a profile', 'apx profile', 'what profiles are there', 'activate the secretary', 'go back to vanilla', 'change my agent's schedule', 'why does it message me'.
Installs into .claude/skills of the current project.
Are you the author of Apx Profile?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/agentprojectcontext-apx-profile)
---
name: apx-profile
description: Agent profiles: installable lines of work — "el perfil", "perfiles disponibles", "instalá un perfil" — secretary, project manager and others. Load when the user wants to install, activate, configure, diagnose or remove one, or asks why the agent behaves the way it does. Triggers: 'install a profile', 'apx profile', 'what profiles are there', 'activate the secretary', 'go back to vanilla', 'change my agent's schedule', 'why does it message me'.
---
# apx-profile
A **profile** is an installable package that gives the super-agent a line of work: a
prompt block, its own routines, and the white-label settings the owner fills in. With no
profile active APX is *vanilla* — the system prompt is byte-identical to a clean install.
Three words that are easy to confuse. Keep them apart:
| Term | What it is | Where it lives |
|---|---|---|
| **profile** | an installable line of work (this skill) | `~/.apx/profiles/`, `config.profile` |
| **persona** | the super-agent's visible NAME | `~/.apx/identity.json` → `agent_name` |
| project config | per-project overrides | `~/.apx/projects/<apx_id>/config.json` |
Installing and activating are **different operations**. `install` validates a package and
makes it reachable; `use` is the moment behaviour changes.
## Concrete CLI calls
```bash
# Discover
apx profile list # everything available, and which is active
apx profile show secretary # settings, token cost, where it came from
apx profile show secretary --preview # ...plus the rendered prompt block
# Install and activate
apx profile install secretary # a bundled id
apx profile install ./my-profile # a local package directory
apx profile use secretary # activates + installs its routines
apx profile use tutor --force # replace whatever is active
apx profile sync # re-read the active package from disk (after an APX update)
# Configure — this is where white-label happens
apx profile config # show current settings
apx profile config --set day_open_schedule="30 8 * * 1-5"
apx profile config --set nudge_budget_per_day=3 --set quiet_hours=22:00-07:30
apx profile config --set watch_schedule="0 */2 * * *" --set formality=vos
apx profile config --interactive # walk the whole schema
# Health and removal
apx profile doctor # what's missing for it to do its job
apx profile off # back to vanilla
apx profile uninstall secretary
```
## What each command actually does
- **`install`** validates the manifest, the schema and every template, then seeds the
settings with the schema defaults. It does **not** activate. A **local path** is copied
into `~/.apx/profiles/`; a **bundled** package is not — it is read in place so a later
`npm update` improves it instead of being shadowed by a stale copy.
- **`use`** writes `config.profile.active`, reloads the prompt, and installs the package's
routines (named `<profile-id>-<routine>`, marked `origin: "profile:<id>"`).
- **`off`** sets `active: null` and **disables** those routines. It deletes nothing —
settings, tasks, commitments and memory all survive, so `use` again restores everything.
- **`config`** validates against the schema and **really reschedules**: changing an opening
time moves the cron, it doesn't just edit JSON.
- **`uninstall`** removes the package and the routines it installed, but **keeps any routine
the user edited** and never touches one the user wrote. A bundled package can't be
deleted, so it gets a tombstone and can be reinstalled any time.
## Settings are per profile
`config.profile.configs[<id>]` holds each profile's own settings; `config.profile.config`
mirrors the active one. Switching A → B → A gives A its settings back rather than handing
it B's.
## When the user asks "why did it message me?"
Read the active profile's prompt block — `apx profile show <id> --preview` — and its
settings. Interruption budgets, quiet hours and staleness thresholds are all profile
settings, not core behaviour. If the answer is "it shouldn't have", the fix is usually
`apx profile config`, not a code change.
## Package layout
```
<id>/
profile.json # manifest: id, name, version, requires, prompt_budget_tokens
PROFILE.md # the always-on prompt block (template)
PROFILE.es.md # optional translations: PROFILE.<lang>.md
config.schema.json # the white-label settings, every one with a default
channels/<ch>.md # optional per-channel overlay, appended after the core file
routines/*.json # routines it installs
agents/*.md # specialists it adds to the vault
skills/<slug>/SKILL.md # its own operational procedures
```
**Template rules, enforced at install time** (installation fails, naming the variable):
- Only flat `{{single_word}}` names. `{{profile.name}}` cannot be substituted and is rejected.
- Every variable must resolve: a built-in (`owner_name`, `agent_name`, `owner_context`,
`profile_name`) or a schema property **with a default**. A property declared without a
default is rejected, because it would silently render as an empty string.
**In `routines/*.json`, settings render as VALUES, not as text.** The file is parsed first
and each string leaf rendered after, so a setting carrying quotes (a shell command with JSON
arguments, say) cannot break the document. Two consequences worth knowing:
- A `pre_commands` / `post_commands` entry that renders empty is dropped entirely, so an
optional command is just a setting defaulting to `""` — no empty shell step, no pre phase.
- `{{pre_output}}` is left alone by the renderer and filled by the routine runner at run
time. That is how a routine hands itself data without spending a tool call or a permission
on it — the secretary's `calendar_command` is the live example.
## A package updates, its installed routines do not
The prompt block is rendered every turn, so it improves the moment APX updates. Routines are
records in the super-agent's store, written at install time — nothing carries a better anchor
across. `apx profile sync` (and any settings save) re-renders them from the package on disk,
leaving settings, activation AND each routine's on/off alone — only `apx profile use` applies the
package's `enabled_by_default`. A package may ship routines OFF (company: only the weekly review
and monthly scorecard start on; the pulse, the decision brief and the councils are installed off —
`apx routine enable <name>` turns one on); `apx profile doctor` reports the drift so it is not silent. A routine the
owner edited is skipped forever, by design, which also means a profile SETTING that lands in
a routine stops taking effect on that routine once they have touched it.
## Channel overlays
`channels/<ch>.md` is rendered and appended after the core `channels/<ch>.md`, only on that
surface. Use it for judgement that must load deterministically where a decision is taken —
the rules for speaking unprompted belong in `channels/routine.md`, not in an on-demand
skill, because "should I interrupt?" is a decision the model may not know it is about to
take. Costs nothing on the channels that don't need it.
## The prompt budget is real
The block ships on **every turn of every channel**, on top of a ~2.5k-token base. A
package declares `prompt_budget_tokens`; exceeding it warns, exceeding 1.5× fails to
install. Check the real number with `apx profile show <id>` or
`node scripts/inspect-channel-prompts.js`.
## HTTP
`GET /api/profiles` · `GET /api/profiles/:id` (includes `preview`) · `GET /api/profiles/doctor` ·
`POST /api/profiles/install` · `POST /api/profiles/use` · `POST /api/profiles/off` ·
`POST /api/profiles/sync` (re-applies a package's routines after an update — `apx profile sync`) ·
`PATCH /api/profiles/config` · `DELETE /api/profiles/:id` ·
`POST /api/profiles/readopt` (force the active profile's routines back to the package, past the
user_modified/user_owned skips sync respects — `{ routine }` targets one, omit for all; the
web "Re-sync routines" button. It discards local edits to the affected routines.)
## Gotchas
- **`install` does not activate.** The most common confusion. Follow it with `use`.
- **One profile at a time.** Activating a second needs `--force`.
- **`off` is not `uninstall`.** `off` is reversible and keeps everything.
- **The vanilla invariant is load-bearing.** With no profile active the prompt must stay
byte-identical. If a change would alter that, it's a bug, not a feature.