@agentprojectcontext/apx 1.34.0 → 1.35.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/package.json +1 -1
  2. package/skills/apx/SKILL.md +1 -1
  3. package/src/core/agent/build-agent-system.js +134 -58
  4. package/src/core/agent/channels/voice-context.js +4 -4
  5. package/src/core/agent/prompt-builder.js +176 -123
  6. package/src/core/agent/prompts/channels/code.md +12 -10
  7. package/src/core/agent/prompts/channels/desktop.md +5 -32
  8. package/src/core/agent/prompts/channels/telegram.md +4 -15
  9. package/src/core/agent/prompts/channels/web_code.md +11 -11
  10. package/src/core/agent/prompts/core/agent-base.md +24 -0
  11. package/src/core/agent/prompts/core/project-agent.md +11 -0
  12. package/src/core/agent/prompts/core/super-agent.md +21 -0
  13. package/src/core/agent/prompts/discipline/action.md +10 -0
  14. package/src/core/agent/prompts/discipline/single-segment.md +6 -0
  15. package/src/core/agent/prompts/discipline/two-segment.md +11 -0
  16. package/src/core/agent/self-memory.js +43 -1
  17. package/src/core/agent/skills/index-store.js +307 -0
  18. package/src/core/agent/skills/index.js +15 -1
  19. package/src/core/agent/skills/inspector.js +317 -0
  20. package/src/core/agent/super-agent.js +7 -1
  21. package/src/core/agent/tools/handlers/_git.js +50 -0
  22. package/src/core/agent/tools/handlers/git-diff.js +44 -0
  23. package/src/core/agent/tools/handlers/git-log.js +38 -0
  24. package/src/core/agent/tools/handlers/git-show.js +34 -0
  25. package/src/core/agent/tools/handlers/git-status.js +61 -0
  26. package/src/core/agent/tools/names.js +31 -0
  27. package/src/core/agent/tools/registry.js +36 -5
  28. package/src/core/config/index.js +21 -0
  29. package/src/core/runtime-skills/apx/SKILL.md +27 -39
  30. package/src/core/runtime-skills/apx-agency-agents/SKILL.md +40 -56
  31. package/src/core/runtime-skills/apx-agent/SKILL.md +27 -30
  32. package/src/core/runtime-skills/apx-mcp/SKILL.md +31 -36
  33. package/src/core/runtime-skills/apx-mcp-builder/SKILL.md +37 -51
  34. package/src/core/runtime-skills/apx-project/SKILL.md +20 -29
  35. package/src/core/runtime-skills/apx-routine/SKILL.md +34 -47
  36. package/src/core/runtime-skills/apx-runtime/SKILL.md +32 -50
  37. package/src/core/runtime-skills/apx-sessions/SKILL.md +96 -145
  38. package/src/core/runtime-skills/apx-skill-builder/SKILL.md +53 -77
  39. package/src/core/runtime-skills/apx-task/SKILL.md +18 -21
  40. package/src/core/runtime-skills/apx-telegram/SKILL.md +43 -54
  41. package/src/core/runtime-skills/apx-voice/SKILL.md +36 -56
  42. package/src/host/daemon/api/skills.js +140 -6
  43. package/src/host/daemon/api/super-agent.js +56 -1
  44. package/src/host/daemon/index.js +17 -0
  45. package/src/interfaces/cli/branding.js +53 -0
  46. package/src/interfaces/cli/commands/skills.js +254 -0
  47. package/src/interfaces/cli/index.js +84 -2
  48. package/src/interfaces/web/dist/assets/index-C0fm31dY.js +618 -0
  49. package/src/interfaces/web/dist/assets/index-C0fm31dY.js.map +1 -0
  50. package/src/interfaces/web/dist/assets/index-UcAqlBO6.css +1 -0
  51. package/src/interfaces/web/dist/index.html +2 -2
  52. package/src/interfaces/web/src/components/chat/MessageBubble.tsx +21 -1
  53. package/src/interfaces/web/src/components/settings/MemoryPanel.tsx +68 -0
  54. package/src/interfaces/web/src/components/settings/SkillsInspectorPanel.tsx +222 -0
  55. package/src/interfaces/web/src/hooks/useChat.ts +19 -0
  56. package/src/interfaces/web/src/i18n/en.ts +1 -0
  57. package/src/interfaces/web/src/i18n/es.ts +1 -0
  58. package/src/interfaces/web/src/lib/api/skills.ts +70 -0
  59. package/src/interfaces/web/src/screens/SettingsScreen.tsx +6 -2
  60. package/src/interfaces/web/src/types/daemon.ts +10 -0
  61. package/src/core/agent/prompts/action-discipline.md +0 -24
  62. package/src/core/agent/prompts/super-agent-base.md +0 -42
  63. package/src/interfaces/web/dist/assets/index-DdmSRtsz.css +0 -1
  64. package/src/interfaces/web/dist/assets/index-M4FspaCH.js +0 -613
  65. package/src/interfaces/web/dist/assets/index-M4FspaCH.js.map +0 -1
@@ -1,24 +1,22 @@
1
1
  ---
2
2
  name: apx-mcp
3
- description: How to register, list, debug, and scope MCP servers in APX. Use BEFORE adding any MCP — three scopes (shared/runtime/global) with different commit and secrecy semantics.
3
+ description: Register, list, debug, scope MCP servers in APX. Load BEFORE adding any MCP — three scopes (shared/runtime/global) with different commit and secrecy semantics. Triggers: 'add MCP', 'apx mcp', 'MCP scope', 'MCP failing', 'list MCPs'.
4
4
  ---
5
5
 
6
6
  # apx-mcp
7
7
 
8
- APX exposes Model Context Protocol (MCP) servers to agents. Three scopes, each in a different file with different rules:
8
+ APX exposes MCP servers via three scopes; resolution priority **runtime > shared > global**, conflicts via `apx mcp check`:
9
9
 
10
10
  | Scope | File | Committed? | Secrets OK? | When |
11
11
  |---|---|---|---|---|
12
- | `shared` | `<repo>/.apc/mcps.json` | yes | **no** | Team-wide MCPs (filesystem, brave, github public) |
13
- | `runtime` | `~/.apx/projects/<apxId>/mcps.json` (chmod 0600) | no | yes | Per-project local — tokens, machine-specific endpoints |
14
- | `global` | `~/.apx/mcps.json` | n/a | yes | Machine-wide not tied to any project |
15
-
16
- Resolution priority when a name appears in more than one: **runtime > shared > global**. Conflicts surface in `apx mcp check`.
12
+ | `shared` | `<repo>/.apc/mcps.json` | yes | **no** | Team-wide (filesystem, brave, github public) |
13
+ | `runtime` | `~/.apx/projects/<apxId>/mcps.json` (chmod 0600) | no | yes | Per-project — tokens, machine-specific endpoints |
14
+ | `global` | `~/.apx/mcps.json` | n/a | yes | Machine-wide, not tied to a project |
17
15
 
18
16
  ## Concrete CLI calls
19
17
 
20
18
  ```bash
21
- # List (all scopes, this is the default)
19
+ # List (defaults to all scopes)
22
20
  apx mcp list --project iacrmar
23
21
  apx mcp list --scope runtime --project iacrmar
24
22
  apx mcp list --scope shared --project iacrmar
@@ -36,34 +34,32 @@ apx mcp add github --scope runtime --project iacrmar \
36
34
  --command npx --env GITHUB_TOKEN=ghp_xxx \
37
35
  -- -y @modelcontextprotocol/server-github
38
36
 
39
- # Add — global (machine-wide, not tied to a project)
37
+ # Add — global (machine-wide)
40
38
  apx mcp add brave --scope global \
41
39
  --command npx --env BRAVE_API_KEY=BSAxxx \
42
40
  -- -y @modelcontextprotocol/server-brave-search
43
41
 
44
- # Remove (pass --scope when the MCP isn't in the default scope:
45
- # shared inside an APC project, else global)
42
+ # Remove (pass --scope when not in default: shared inside APC project, else global)
46
43
  apx mcp remove filesystem --project iacrmar
47
44
  apx mcp remove github --scope runtime --project iacrmar
48
45
 
49
- # Toggle (defaults to the scope that owns the MCP)
46
+ # Toggle (defaults to owning scope)
50
47
  apx mcp enable filesystem --project iacrmar
51
48
  apx mcp disable filesystem --project iacrmar
52
49
 
53
- # Call a tool through the daemon (useful for debugging)
50
+ # Call a tool through the daemon (debugging)
54
51
  apx mcp run filesystem read_file '{"path":"README.md"}'
55
52
  ```
56
53
 
57
- ## When the user asks for a new MCP
54
+ ## Scope decision tree
58
55
 
59
- Decision tree:
60
- 1. **Has secrets / tokens?** → `runtime` scope. Always.
61
- 2. **Is part of the project's shared dev environment?** → `shared` (committed).
56
+ 1. **Has secrets/tokens?** → `runtime`. Always.
57
+ 2. **Part of project's shared dev environment?** → `shared` (committed).
62
58
  3. **Used across all your projects?** → `global`.
63
59
 
64
- Default if none is obvious: `shared` when inside an APC project, `global` outside.
60
+ Default if unclear: `shared` inside an APC project, `global` outside.
65
61
 
66
- ## Common command shapes by transport
62
+ ## Command shapes by transport
67
63
 
68
64
  ```bash
69
65
  # stdio MCP (most common — npx, uvx, node, python)
@@ -78,39 +74,38 @@ apx mcp add <name> --command npx \
78
74
  -- -y @modelcontextprotocol/server-github
79
75
  ```
80
76
 
81
- Anything after `--` is forwarded verbatim as args to the command. Quote carefully.
77
+ Everything after `--` is forwarded verbatim as args. Quote carefully.
82
78
 
83
79
  ## Anti-examples
84
80
 
85
81
  ```bash
86
- # DON'T put tokens in shared scope. It commits.
82
+ # DON'T put tokens in shared scope it commits.
87
83
  apx mcp add github --scope shared --env GITHUB_TOKEN=ghp_xxx ...
88
84
  # ↑ Token ends up in .apc/mcps.json in your repo. Use --scope runtime.
89
85
 
90
- # DON'T remove an MCP from the wrong scope.
91
- apx mcp remove github # if github lives in runtime, this errors with a hint
92
- # ↑ Daemon returns 409 with the right scope to use.
86
+ # DON'T remove from the wrong scope — daemon returns 409 with the right scope.
87
+ apx mcp remove github # errors if github lives in runtime
93
88
 
94
- # DON'T expect IDE-foreign configs (~/.cursor/mcps.json, ~/.claude/mcps.json) to be
95
- # removable via apx mcp remove. APX reads them as advisory (source=cursor/claude/etc)
89
+ # DON'T expect IDE-foreign configs (~/.cursor/mcps.json, ~/.claude/mcps.json)
90
+ # to be removable via apx mcp remove. APX reads them advisory (source=cursor/claude)
96
91
  # but won't write them. Edit the IDE config directly.
97
92
  ```
98
93
 
99
- ## Debugging connection issues
94
+ ## Debugging
100
95
 
101
96
  ```bash
102
- apx mcp check --project iacrmar # what scopes APX sees + which files exist
103
- apx mcp run <name> <tool> '{...}' # spawn the server and call a tool for real
104
- apx log -f # tail unified log for spawn errors
97
+ apx mcp check --project iacrmar # scopes seen + which files exist
98
+ apx mcp run <name> <tool> '{...}' # spawn server, call a tool
99
+ apx log -f # tail unified log for spawn errors
105
100
  ```
106
101
 
107
- A server that "doesn't show tools" usually means: the command failed to start (env vars missing, package not found), or the server crashed during initialize. The unified log has the stderr buffer.
102
+ "Doesn't show tools" = command failed to start (missing env vars, package not found) or crashed during initialize. Unified log holds the stderr buffer.
108
103
 
109
- > `apx mcp tools <name>` is a placeholder stub (prints a "coming in v0.2" notice, lists nothing). To verify a server actually spawns, call a tool with `apx mcp run`.
104
+ > `apx mcp tools <name>` is a placeholder stub ("coming in v0.2"). Use `apx mcp run` to verify spawn.
110
105
 
111
106
  ## Don't
112
107
 
113
- - Don't mix scopes for the same MCP name unless you actually want shadowing. The result is "the one with highest priority wins, others stay invisible."
114
- - Don't edit `~/.apx/projects/<id>/mcps.json` by hand; use `apx mcp add --scope runtime`. The file is chmod 0600 — the CLI keeps it that way.
115
- - Don't add tokens via `--env KEY=` inline if your shell history is public. Set them in your shell first, then `--env KEY=$KEY`.
116
- - Don't forget to `apx daemon reload` after editing config — actually `apx mcp` does this for you, but if you hand-edited the JSON, it's manual.
108
+ - Don't mix scopes for the same MCP name unless you want shadowing highest priority wins, others stay invisible.
109
+ - Don't edit `~/.apx/projects/<id>/mcps.json` by hand; use `apx mcp add --scope runtime` (the file is chmod 0600 — CLI preserves it).
110
+ - Don't put tokens via `--env KEY=` inline if shell history is public. Set them in your shell first, then `--env KEY=$KEY`.
111
+ - Don't forget to `apx daemon reload` after hand-editing JSON. `apx mcp` does this for you.
@@ -1,33 +1,31 @@
1
1
  ---
2
2
  name: apx-mcp-builder
3
3
  scope: internal
4
- description: How to build a Model Context Protocol (MCP) server from scratch and register it in APX. Load when authoring a new MCP / exposing a new tool surface to agents. Covers the JSON-RPC stdio protocol, FastMCP (Python) / TypeScript SDK shapes, and APX registration.
4
+ description: Author a new MCP (Model Context Protocol) server and register it in APX. Covers JSON-RPC stdio protocol, FastMCP (Python) / TypeScript SDK shapes, tool design, secrets, debugging. Load when building a new MCP / exposing a new tool surface. To add an existing MCP, load `apx-mcp` instead.
5
5
  ---
6
6
 
7
7
  # apx-mcp-builder
8
8
 
9
- A **Model Context Protocol** server is a tiny process the agent talks to over stdio JSON-RPC. APX spawns it (via `apx mcp add`), discovers its tools (`tools/list`), and lets the super-agent call them by name. This skill is for **authoring a new MCP server**. To **add an existing one** to APX, load `apx-mcp` instead.
9
+ An MCP server is a tiny stdio JSON-RPC process. APX spawns it (via `apx mcp add`), discovers tools (`tools/list`), and lets the super-agent call them by name.
10
10
 
11
- ## The minimum surface
12
-
13
- An MCP server must implement four RPC methods:
11
+ ## Minimum surface
14
12
 
15
13
  | Method | Purpose | Returns |
16
14
  |---|---|---|
17
- | `initialize` | Handshake. APX sends protocol version + capabilities. | Server's capabilities. |
18
- | `tools/list` | Enumerate available tools. | `{ tools: [{name, description, inputSchema}] }` |
19
- | `tools/call` | Run one tool. APX sends `{ name, arguments }`. | `{ content: [...], isError? }` |
20
- | `notifications/initialized` | One-way; APX signals it's done initializing. | — |
15
+ | `initialize` | Handshake (protocol version + capabilities). | Server capabilities. |
16
+ | `tools/list` | Enumerate tools. | `{ tools: [{name, description, inputSchema}] }` |
17
+ | `tools/call` | Run one tool with `{ name, arguments }`. | `{ content: [...], isError? }` |
18
+ | `notifications/initialized` | One-way init-done from APX. | — |
21
19
 
22
- JSON-RPC 2.0 framing over stdio. Each message: `Content-Length: N\r\n\r\n<JSON>`. The `@modelcontextprotocol/sdk` (TS) and `fastmcp` / `mcp` (Python) packages handle framing for you.
20
+ JSON-RPC 2.0 over stdio, framed `Content-Length: N\r\n\r\n<JSON>`. The `@modelcontextprotocol/sdk` (TS) and `fastmcp` / `mcp` (Python) packages handle framing.
23
21
 
24
22
  ## Pick a stack
25
23
 
26
24
  | Stack | When |
27
25
  |---|---|
28
- | **Python + FastMCP** | Fastest path. Decorator-based. Great if your tools wrap pip libs. |
29
- | **Node + @modelcontextprotocol/sdk** | When the tool calls Node-only libs, or you want zero install (`npx -y`). |
30
- | Raw JSON-RPC | Only if you have an existing daemon you want to expose. Otherwise SDK. |
26
+ | **Python + FastMCP** | Fastest path; decorator-based; ideal for pip-wrapping tools. |
27
+ | **Node + @modelcontextprotocol/sdk** | Node-only libs, or zero install (`npx -y`). |
28
+ | Raw JSON-RPC | Only when exposing an existing daemon. Otherwise use the SDK. |
31
29
 
32
30
  ## Python (FastMCP) — minimum viable server
33
31
 
@@ -40,7 +38,6 @@ mcp = FastMCP("my-server")
40
38
  @mcp.tool()
41
39
  def search_inventory(query: str, limit: int = 10) -> list[dict]:
42
40
  """Search the inventory by free-text query. Returns matching SKUs."""
43
- # ... your logic ...
44
41
  return [{"sku": "abc", "title": "..."}]
45
42
 
46
43
  @mcp.tool()
@@ -49,18 +46,13 @@ def get_stock(sku: str) -> dict:
49
46
  return {"sku": sku, "stock": 42}
50
47
 
51
48
  if __name__ == "__main__":
52
- mcp.run() # stdio transport by default
49
+ mcp.run() # stdio transport
53
50
  ```
54
51
 
55
- Install:
56
52
  ```bash
57
53
  pip install fastmcp
58
- # or via uv (recommended):
59
- uv tool install fastmcp
60
- ```
54
+ # or: uv tool install fastmcp
61
55
 
62
- Register in APX:
63
- ```bash
64
56
  apx mcp add my-server \
65
57
  --command uv --project iacrmar \
66
58
  -- run python /abs/path/my_server.py
@@ -102,7 +94,6 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
102
94
  server.setRequestHandler(CallToolRequestSchema, async (req) => {
103
95
  if (req.params.name === "search_inventory") {
104
96
  const { query, limit = 10 } = req.params.arguments as any;
105
- // ... your logic ...
106
97
  return {
107
98
  content: [{ type: "text", text: JSON.stringify([{ sku: "abc" }]) }],
108
99
  };
@@ -113,7 +104,6 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
113
104
  await server.connect(new StdioServerTransport());
114
105
  ```
115
106
 
116
- Register:
117
107
  ```bash
118
108
  apx mcp add my-server \
119
109
  --command npx --project iacrmar \
@@ -122,16 +112,14 @@ apx mcp add my-server \
122
112
 
123
113
  ## Tool design rules
124
114
 
125
- 1. **Names are snake_case**, verbs preferred: `search_inventory`, not `inventorySearch`.
126
- 2. **inputSchema is JSON Schema draft-07**. Be strict: `required` matters. The agent reads the schema; vague schemas → bad calls.
127
- 3. **Descriptions read like a CLI man-page**. Each tool's description and each param's description gets surfaced to the model. Make them count.
128
- 4. **Return structured data**, not prose. MCP `content` can be text but the convention is to put JSON inside a text block so the agent can parse it back. For images, use the `image` content type.
129
- 5. **Errors are errors, not silent empty**. `throw new Error(...)` propagates as `isError: true` and the agent will see it. Empty results = "found nothing"; that's a different signal.
115
+ 1. **Names are snake_case verbs**: `search_inventory`, not `inventorySearch`.
116
+ 2. **inputSchema is JSON Schema draft-07**. `required` matters vague schemas → bad calls.
117
+ 3. **Descriptions read like a man-page**. Tool + param descriptions are surfaced to the model.
118
+ 4. **Return structured data**, not prose. Convention: JSON inside a text content block. Images use the `image` type.
119
+ 5. **Errors are errors**: `throw new Error(...)` propagates as `isError: true`. Empty result = "found nothing" different signal.
130
120
 
131
121
  ## Env vars and secrets
132
122
 
133
- Pass them at registration time via `--env`:
134
-
135
123
  ```bash
136
124
  apx mcp add github \
137
125
  --scope runtime --project iacrmar \
@@ -141,43 +129,41 @@ apx mcp add github \
141
129
  -- -y @modelcontextprotocol/server-github
142
130
  ```
143
131
 
144
- `--scope runtime` writes to `~/.apx/projects/<id>/mcps.json` (chmod 0600, never committed). NEVER use `--scope shared` for tokens — that file lives in `.apc/` and gets committed.
132
+ `--scope runtime` writes to `~/.apx/projects/<id>/mcps.json` (chmod 0600, never committed). NEVER `--scope shared` for tokens — that file lives in `.apc/` and gets committed.
145
133
 
146
134
  ## Anti-examples
147
135
 
148
136
  ```python
149
- # DON'T expose every internal function as a tool.
150
- # A server with 40 tools is a context budget killer. Pick 5-10 high-value
151
- # tools per server; split into multiple servers if you have more.
137
+ # DON'T expose every internal function. A server with 40 tools eats context.
138
+ # Pick 5-10 high-value tools per server; split into multiple servers if more.
152
139
 
153
- # DON'T return giant blobs in `content`. The agent has to read all of it
154
- # every turn. Paginate (`offset`, `limit`) and let the agent ask for more.
140
+ # DON'T return giant blobs in `content`. The agent re-reads every turn.
141
+ # Paginate (`offset`, `limit`) and let the agent ask for more.
155
142
 
156
- # DON'T mix stdio + HTTP transports in the same process. Pick one. APX
157
- # spawns stdio servers; if you want HTTP, use `url:` in mcps.json instead
158
- # of `command:`.
143
+ # DON'T mix stdio + HTTP transports in one process. APX spawns stdio;
144
+ # for HTTP use `url:` in mcps.json instead of `command:`.
159
145
 
160
- # DON'T print to stdout other than JSON-RPC frames. Any stray print()
161
- # corrupts the protocol — use stderr for logs. (FastMCP / the SDK handle
162
- # this for you, but `print("debug")` in a tool body breaks everything.)
146
+ # DON'T print to stdout outside JSON-RPC frames. Stray print() corrupts
147
+ # the protocol — use stderr for logs. (SDKs handle this; bare `print("debug")`
148
+ # in a tool body breaks everything.)
163
149
  ```
164
150
 
165
- ## Common debugging path
151
+ ## Debugging
166
152
 
167
153
  ```bash
168
- # 1. Does the server start + does a tool work? (apx mcp tools is a v0.2 stub — don't rely on it)
154
+ # Smoke test (apx mcp tools is a v0.2 stub — don't rely on it)
169
155
  apx mcp run my-server search_inventory '{"query":"shoes"}'
170
156
 
171
- # 2. Are there spawn errors?
172
- apx log -f # tail the daemon log — stderr lands here
157
+ # Spawn errors / stderr
158
+ apx log -f
173
159
 
174
- # 3. What scopes/files + env does APX see?
160
+ # Scopes / files / env APX sees
175
161
  apx mcp check --project iacrmar
176
162
  ```
177
163
 
178
164
  ## Don't
179
165
 
180
- - Don't reinvent the SDK framing. FastMCP / @modelcontextprotocol/sdk handle the stdio JSON-RPC dance — bypass only if you really need to.
181
- - Don't make tools that require interactive input. MCP is one-shot per call. If you need a flow, design separate tools for each step.
182
- - Don't ship a server without a README in the repo. Future-you will not remember which env vars matter.
183
- - Don't expect APX to retry MCP errors automatically. The agent sees the error and decides.
166
+ - Don't reinvent SDK framing — bypass only with reason.
167
+ - Don't make interactive tools. MCP is one-shot per call; split flows into multiple tools.
168
+ - Don't ship without a README future-you forgets which env vars matter.
169
+ - Don't expect APX to retry MCP errors. The agent sees the error and decides.
@@ -1,30 +1,30 @@
1
1
  ---
2
2
  name: apx-project
3
- description: How to register, list, configure, and manage APX projects. Use BEFORE asking the user "which project?" — registered projects are listable; per-project config (model override, etc) is set with dotted-key PATCH.
3
+ description: Register, list, configure, manage APX projects. Load BEFORE asking "which project?" — registered projects are listable; per-project config set via dotted-key PATCH. Triggers: 'register project', 'apx project', 'project config', 'list projects', 'what projects are registered'.
4
4
  ---
5
5
 
6
6
  # apx-project
7
7
 
8
- A project in APX is an APC-compliant folder on disk (`AGENTS.md` + `.apc/project.json`). Once registered, APX keeps runtime state (sessions, messages, routines, tasks, MCPs) under `~/.apx/projects/<apxId>/`.
8
+ A project in APX is an APC-compliant folder (`AGENTS.md` + `.apc/project.json`). Once registered, APX keeps runtime state (sessions, messages, routines, tasks, MCPs) under `~/.apx/projects/<apxId>/`.
9
9
 
10
- ## The two kinds of projects
10
+ ## Two kinds of projects
11
11
 
12
- - **`default`** (id=0): the super-agent's scratch workspace under `~/.apx/projects/default/`. Used when the user has no project named, has no project registered, or explicitly addresses "apx itself". Don't use it for real work — it's shared.
12
+ - **`default`** (id=0): super-agent's scratch workspace at `~/.apx/projects/default/`. Used when user has no project named, no project registered, or addresses "apx itself". Don't use for real work — shared.
13
13
  - **registered** (id=1+): real projects, each rooted at a path the user owns.
14
14
 
15
15
  ## Concrete CLI calls
16
16
 
17
17
  ```bash
18
18
  # Register
19
- apx project add /path/to/repo # registers; reads AGENTS.md + .apc/project.json
19
+ apx project add /path/to/repo # reads AGENTS.md + .apc/project.json
20
20
  apx project add . # current dir
21
21
 
22
22
  # Inspect
23
23
  apx project list # id, name, agents count, path
24
24
 
25
- # Remove / rebuild (id or exact path only — these do NOT resolve by name)
25
+ # Remove / rebuild (id or exact path only — no name resolution here)
26
26
  apx project remove <id|path>
27
- apx project rebuild <id|path> # force re-scan of .apc/ on disk
27
+ apx project rebuild <id|path> # force re-scan of .apc/
28
28
 
29
29
  # Per-project config — dotted keys, lives in <repo>/.apc/config.json
30
30
  apx project config show <project> # effective + project_only
@@ -36,17 +36,11 @@ apx project config unset <project> super_agent.model # back to glo
36
36
  apx project config edit <project> # opens $EDITOR on project_only JSON
37
37
  ```
38
38
 
39
- Every write to `project config` triggers `POST /admin/reload` so the daemon picks up the change without restart.
39
+ Every `project config` write triggers `POST /admin/reload` so the daemon picks up changes without restart.
40
40
 
41
- ## Resolution of `<project>` argument
41
+ ## `<project>` argument resolution
42
42
 
43
- Accepted forms:
44
- - numeric id: `1`
45
- - exact name from `.apc/project.json`: `iacrmar`
46
- - absolute path: `/Volumes/SSDT7Shield/trabajos_proyectos/iacrmar`
47
- - relative path (from cwd) — resolved before matching.
48
-
49
- The CLI calls `resolveProjectId()` which does fuzzy id-or-name-or-path matching. If you got "project not found", `apx project list` first.
43
+ Accepted: numeric id (`1`), exact name from `.apc/project.json` (`iacrmar`), absolute path, relative path (resolved from cwd). The CLI's `resolveProjectId()` does fuzzy id/name/path matching. If "project not found", run `apx project list` first.
50
44
 
51
45
  ## What lives where
52
46
 
@@ -59,7 +53,7 @@ The CLI calls `resolveProjectId()` which does fuzzy id-or-name-or-path matching.
59
53
  ├── skills/<slug>.md or <slug>/SKILL.md
60
54
  ├── mcps.json ← shared MCPs (committed)
61
55
  ├── commands/ ← custom slash-commands
62
- └── config.json ← project-only overrides (this is what `project config` edits)
56
+ └── config.json ← project-only overrides (edited by `project config`)
63
57
 
64
58
  ~/.apx/projects/<apxId>/ ← runtime state (never committed)
65
59
  ├── messages/YYYY-MM-DD.jsonl
@@ -70,29 +64,26 @@ The CLI calls `resolveProjectId()` which does fuzzy id-or-name-or-path matching.
70
64
  └── mcps.json ← per-project runtime MCPs (local, may hold tokens)
71
65
  ```
72
66
 
73
- ## Anti-example
67
+ ## Anti-examples
74
68
 
75
69
  ```bash
76
70
  # DON'T hand-write AGENTS.md + .apc/project.json with shell tools.
77
71
  echo "Hello" > /path/repo/AGENTS.md
78
- mkdir -p /path/repo/.apc
79
- echo "{...}" > /path/repo/.apc/project.json
80
- ```
72
+ mkdir -p /path/repo/.apc && echo "{...}" > /path/repo/.apc/project.json
73
+ # No scaffold validation; project appears registered but breaks on `apx project rebuild`.
74
+ # Use `apx init <path>` then `apx project add <path>`.
81
75
 
82
- There's no scaffold validation, the project will appear registered but break on the first `apx project rebuild`. Use `apx init <path>` (project scaffold) and then `apx project add <path>`.
83
-
84
- ```bash
85
- # DON'T set super_agent.model to a model that's not in the engine you have keys for.
76
+ # DON'T set super_agent.model to a model lacking an engine key.
86
77
  apx project config set iacrmar super_agent.model gemini:gemini-1.5-pro
87
- # ↑ Will fail at first call unless engines.gemini.api_key is set.
78
+ # ↑ Fails at first call unless engines.gemini.api_key is set.
88
79
  ```
89
80
 
90
81
  ## When asked "what projects are there?"
91
82
 
92
- Don't ask. Call `list_projects` (tool) or `apx project list`. Same for "which agents does X have?" → `list_agents` / `apx agent list --project X`.
83
+ Don't ask call `list_projects` tool or `apx project list`. Same for "which agents does X have?" → `list_agents` / `apx agent list --project X`.
93
84
 
94
85
  ## Don't
95
86
 
96
- - Don't operate on the default project (id=0) as if it were the user's main work. It's a scratch space for super-agent state.
87
+ - Don't operate on the default project (id=0) as if it were the user's main work. Scratch space for super-agent state.
97
88
  - Don't put secrets in `.apc/config.json` — it's committed. Put them in `~/.apx/config.json` (machine-local) under `engines.*` or `voice.tts.*`.
98
- - Don't move a project's `.apc/` folder without re-running `apx project rebuild` afterwards. The `apxId` will be stale.
89
+ - Don't move a project's `.apc/` folder without re-running `apx project rebuild` `apxId` will be stale.
@@ -1,35 +1,31 @@
1
1
  ---
2
2
  name: apx-routine
3
- description: How to create, edit, run, and debug APX routines. Use BEFORE writing any `apx routine add` command — schedule grammar, kind selection, pre/post commands, and the gotchas that produce double-replies.
3
+ description: Create, edit, run, debug APX routines (scheduled tasks). Load BEFORE `apx routine add` — schedule grammar, kind selection, pre/post hooks, double-reply gotcha.
4
4
  ---
5
5
 
6
6
  # apx-routine
7
7
 
8
- A routine is a scheduled APX task. APX runs the scheduler tick every 5s and fires routines that are due. Each routine has a `kind`, a `schedule`, an optional `spec`, and optional `pre_commands` / `post_commands` shell hooks.
8
+ A scheduled APX task. Scheduler ticks every 5s. Each routine has a `kind`, `schedule`, optional `spec`, and optional `pre_commands` / `post_commands` shell hooks.
9
9
 
10
- ## When to use which `kind`
10
+ ## Picking `kind`
11
11
 
12
12
  | Kind | Tools? | Description |
13
13
  |---|---|---|
14
- | `heartbeat` | no | Logs a marker message. Useful as a "still alive" ping. No LLM call. |
15
- | `shell` | no | Pure shell command. No LLM. Stdout captured. |
16
- | `exec_agent` | **no tools** | Loads a project agent's system prompt, sends `spec.prompt` to the engine, returns plain text. Single LLM call. |
17
- | `super_agent` | **all tools** | Runs the APX default agent (super-agent mode) with the full tool registry. Multi-iteration tool loop. |
18
- | `telegram` | n/a | Sends a hardcoded text via the Telegram plugin. |
19
-
20
- **Picking rule of thumb**:
21
- - Just need text from a model? → `exec_agent`.
22
- - Need orchestration (call MCPs, write files, call other agents, send messages with logic)? → `super_agent`.
23
- - Pure shell (curl + jq + write somewhere)? → `shell`.
24
- - Periodic Telegram poke with fixed text? → `telegram`.
14
+ | `heartbeat` | no | "Still alive" marker. No LLM. |
15
+ | `shell` | no | Pure shell. Stdout captured. |
16
+ | `exec_agent` | **no** | Loads agent prompt, sends `spec.prompt`, returns text. Single LLM call. |
17
+ | `super_agent` | **all** | Default agent with full tool registry. Multi-iteration loop. |
18
+ | `telegram` | n/a | Sends hardcoded text via Telegram plugin. |
19
+
20
+ Rule: text from model → `exec_agent`; orchestration (MCPs, files, multi-agent) → `super_agent`; pure shell → `shell`; fixed Telegram poke → `telegram`.
25
21
 
26
22
  ## Schedule grammar
27
23
 
28
24
  - `every:<N><unit>` — `every:30s`, `every:5m`, `every:24h`, `every:7d`. **Most common.**
29
- - `once:<iso-8601>` — `once:2026-12-01T08:00:00Z`. Fires once at that instant, then disabled.
30
- - Cron — `*/5 * * * *`, `0 8 * * *`. Standard 5-field. Use only if you really need cron expressions.
25
+ - `once:<iso-8601>` — `once:2026-12-01T08:00:00Z`. Fires once, then disabled.
26
+ - Cron — `*/5 * * * *`, `0 8 * * *`. Standard 5-field.
31
27
 
32
- ## Anatomy of a routine
28
+ ## Anatomy
33
29
 
34
30
  ```json
35
31
  {
@@ -44,12 +40,9 @@ A routine is a scheduled APX task. APX runs the scheduler tick every 5s and fire
44
40
  }
45
41
  ```
46
42
 
47
- **The pipeline**:
48
- 1. `pre_commands` run sequentially. Their combined stdout becomes `{{pre_output}}` substitutable in `spec.prompt`, and `$APX_PRE_OUTPUT` env var available to `post_commands`. Also written to `$APX_PRE_OUTPUT_FILE` for big payloads.
49
- 2. The handler for `kind` runs. Its text result is exposed to post hooks as `$APX_LLM_OUTPUT`.
50
- 3. `post_commands` run sequentially with that env.
43
+ Pipeline: `pre_commands` run sequentially → combined stdout becomes `{{pre_output}}` in `spec.prompt` and `$APX_PRE_OUTPUT` (plus `$APX_PRE_OUTPUT_FILE` for big payloads) → handler runs, result becomes `$APX_LLM_OUTPUT` → `post_commands` run.
51
44
 
52
- ## Anti-example: the double-reply
45
+ ## Anti-example: double-reply
53
46
 
54
47
  ```json
55
48
  {
@@ -59,28 +52,24 @@ A routine is a scheduled APX task. APX runs the scheduler tick every 5s and fire
59
52
  }
60
53
  ```
61
54
 
62
- This sends **two** Telegram messages: one from the super-agent's `send_telegram` tool call, one from `post_commands`. The runner now auto-suppresses `send_telegram` when `post_commands` contains `apx telegram send` (see spec/done/01), but the cleaner fix is to use `exec_agent`:
55
+ Sends **two** messages: one from agent's `send_telegram` tool, one from `post_commands`. The runner auto-suppresses `send_telegram` when post contains `apx telegram send`, but the clean fix is `exec_agent`:
63
56
 
64
57
  ```json
65
58
  {
66
59
  "kind": "exec_agent",
67
- "spec": { "agent": "default", "prompt": "The weather is {{pre_output}}. One friendly sentence, no greeting." },
60
+ "spec": { "agent": "default", "prompt": "The weather is {{pre_output}}. One friendly sentence." },
68
61
  "post_commands": ["apx telegram send \"$APX_LLM_OUTPUT\""]
69
62
  }
70
63
  ```
71
64
 
72
- One message, the model writes prose, the shell pipes it to Telegram.
73
-
74
65
  ## Concrete CLI calls
75
66
 
76
67
  ```bash
77
- # List routines per project (always pin --project; never use default for real ones)
68
+ # Always pin --project; never use default for real ones
78
69
  apx routine list --project iacrmar
70
+ apx routine get weather-bariloche --project iacrmar
79
71
 
80
- # Inspect one
81
- apx routine get weather-bariloche --project iacrmar
82
-
83
- # Create — text-only exec_agent + shell delivery
72
+ # Create — exec_agent + shell delivery
84
73
  apx routine add weather-bariloche \
85
74
  --project iacrmar \
86
75
  --kind exec_agent \
@@ -97,7 +86,7 @@ apx routine add daily-status \
97
86
  --spec '{"prompt":"List projects with pending tasks and send me a short summary via Telegram."}' \
98
87
  --permission-mode automatico
99
88
 
100
- # Toggle, run, remove
89
+ # Toggle / run / remove
101
90
  apx routine enable weather-bariloche --project iacrmar
102
91
  apx routine disable weather-bariloche --project iacrmar
103
92
  apx routine run weather-bariloche --project iacrmar # force-trigger now
@@ -106,23 +95,21 @@ apx routine remove weather-bariloche --project iacrmar
106
95
 
107
96
  ## `--project` is non-negotiable
108
97
 
109
- Routines live in `~/.apx/projects/<apxId>/routines.json`. Without `--project`, the default project (id=0, the super-agent's scratch workspace) gets the routine that is **not** a user project. Always pass `--project <name|id|path>`.
98
+ Routines live in `~/.apx/projects/<apxId>/routines.json`. Without `--project`, they go to default (id=0, super-agent scratch) — **not** a user project. Always pass `--project <name|id|path>`.
110
99
 
111
100
  ## `skip_prompt_on`
112
101
 
113
- Controls whether the LLM call is skipped based on the `pre_commands` result (`shouldSkipPrompt` in `host/daemon/routines.js`):
102
+ Gates the LLM call based on `pre_commands` (`shouldSkipPrompt` in `host/daemon/routines.js`). Post-commands always run.
114
103
 
115
- | Value | Skips the LLM when… |
104
+ | Value | Skips LLM when… |
116
105
  |---|---|
117
- | `signal` (default) | a pre_command prints the literal marker `APX_SKIP` to stdout. A non-zero exit alone does **not** skip. |
106
+ | `signal` (default) | pre_command prints literal `APX_SKIP`. Non-zero exit alone does NOT skip. |
118
107
  | `pre_failure` | any pre_command exits non-zero. |
119
- | `pre_success` | the pre_commands exit 0 (i.e. run the LLM only on pre failure). |
120
- | `always` | unconditionally — pure pre→post pipeline, no LLM. |
121
- | `never` | never — the LLM always runs, even if pre crashes. |
122
-
123
- Post-commands run regardless of the skip decision. The skip only gates the `kind` handler (the LLM call).
108
+ | `pre_success` | pre_commands exit 0 (LLM only on pre failure). |
109
+ | `always` | unconditionally — pure pre→post, no LLM. |
110
+ | `never` | LLM always runs, even if pre crashes. |
124
111
 
125
- ## Debugging a routine
112
+ ## Debugging
126
113
 
127
114
  ```bash
128
115
  apx routine history weather-bariloche --project iacrmar # last runs
@@ -130,11 +117,11 @@ apx log -f # tail unified log
130
117
  apx messages tail --channel routine -n 20 # routine-channel messages
131
118
  ```
132
119
 
133
- A routine that "sends nothing" most often means: (a) `enabled: false`, (b) `next_run_at` is in the future, (c) the LLM returned empty text visible in `apx messages` or in the `result.text` of `apx routine run`.
120
+ "Sends nothing" usually means: `enabled: false`, `next_run_at` in the future, or empty LLM text (check `apx messages` or `result.text`).
134
121
 
135
122
  ## Don't
136
123
 
137
- - Don't use `super_agent` when `exec_agent` would do. The super-agent loops, calls tools, costs more.
138
- - Don't write `apx telegram send` inside a `super_agent` routine prompt — the agent will call `send_telegram` AND `post_commands` will fire. Pick one.
139
- - Don't hardcode model names in `spec` unless you have a reason — the routine inherits `super_agent.model` (with router fallback) by default.
140
- - Don't put credentials in routine `spec`. Put them in `~/.apx/config.json` engines and reference them by provider.
124
+ - Use `super_agent` when `exec_agent` would do it loops, calls tools, costs more.
125
+ - Write `apx telegram send` inside a `super_agent` prompt — agent calls `send_telegram` AND post_commands fire. Pick one.
126
+ - Hardcode model names in `spec` without reason — routines inherit `super_agent.model` (with router fallback).
127
+ - Put credentials in `spec`. Use `~/.apx/config.json` engines and reference by provider.