@agentprojectcontext/apx 1.80.1 → 1.81.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentprojectcontext/apx",
3
- "version": "1.80.1",
3
+ "version": "1.81.0",
4
4
  "description": "APX — unified CLI + daemon for the Agent Project Context (APC) standard.",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -5,7 +5,7 @@
5
5
  "permission_mode": "permiso",
6
6
  "enabled_by_default": true,
7
7
  "spec": {
8
- "prompt": "Close the day. Review what moved today, what is still stuck, and what carries over to tomorrow, across every registered project. Call list_tasks and list_commitments ONCE each, with no project argument both search every project in a single call. Do not loop over projects. If a commitment came due today, ask whether it was kept do not mark it yourself.\n\nSend ONE short message covering those, keeping promises to people separate from ordinary tasks. Note anything that has gone quiet longer than the staleness threshold. If the day was quiet, say that plainly in a line or two.\n\nThen record anything durable you learned about how this person works with remember_routine — one line. Never write_file for this: a scheduled run has nobody to approve it and the whole turn dies there.\n\nDELIVERY: send it with send_telegram. A routine's own output is only written to the log — if you do not call the tool, {{owner_name}} receives nothing at all. Send exactly one message, then stop; do not end the turn by asking whether to keep looking.",
8
+ "prompt": "Close the day, across every registered project.\n\nHOW TO SPEND YOUR STEPS. You get a small, fixed number of tool calls, and the LAST one is taken away from you to write your closing prose — so a turn spent exploring ends with nothing delivered. Gather with list_tasks and list_commitments (once each, no project argument) and NOTHING ELSE. Do not search sessions, do not read files, do not run shell commands: none of that is what {{owner_name}} asked for. Then send, immediately. Report what you actually have; an honest short message beats a complete one that never arrives.\n\nSend ONE short message with three things: what moved today, what is still stuck, and what carries over. Keep promises to people separate from ordinary tasks — if a commitment came due today, ask whether it was kept rather than marking it yourself. Note anything that has gone quiet longer than the staleness threshold. If the day was quiet, say that plainly in a line.\n\nDELIVERY: send_telegram. A routine's own output is only written to the log — if you do not call the tool, {{owner_name}} receives nothing at all. One message, then stop.\n\nAfter sending, record with remember_routine anything durable you learned about how this person works — one line. Never write_file for this: a scheduled run has nobody to approve it and the whole turn dies there.",
9
9
  "anchor": true
10
10
  },
11
11
  "allowed_tools": [
@@ -5,7 +5,7 @@
5
5
  "permission_mode": "permiso",
6
6
  "enabled_by_default": true,
7
7
  "spec": {
8
- "prompt": "Open the day. Look at what is due today, what is overdue, what is blocked, and what is promised, across every registered project. Call list_tasks and list_commitments ONCE each, with no project argument both search every project in a single call. Do not loop over projects. Lead with promises: a broken promise costs more than a late task, so it goes first and is named as a promise to a person, never folded into the task list.\n\nThen send ONE short message: promises coming due or already past, what is due today, anything on the calendar, and the single thing that most deserves attention. Not an inventory.\n\nIf there is genuinely nothing pressing, say so in one line — and then do the thing a chief of staff does with an empty morning: ask what should go on today's list, or name the one stale project worth picking up. An empty day is a prompt, not a silence.\n\nDELIVERY: send it with send_telegram. A routine's own output is only written to the log — if you do not call the tool, {{owner_name}} receives nothing at all. Send exactly one message, then stop; do not end the turn by asking whether to keep looking.",
8
+ "prompt": "Open the day. Look at what is due today, what is overdue, what is blocked, and what is promised, across every registered project. HOW TO SPEND YOUR STEPS. You get a small, fixed number of tool calls, and the LAST one is taken away from you to write your closing prose — so a turn spent exploring ends with nothing delivered. Gather with list_tasks and list_commitments (once each, no project argument) and NOTHING ELSE. Do not search sessions, do not read files, do not run shell commands: none of that is what {{owner_name}} asked for. Then send, immediately. Report what you actually have; an honest short message beats a complete one that never arrives. Lead with promises: a broken promise costs more than a late task, so it goes first and is named as a promise to a person, never folded into the task list.\n\nThen send ONE short message: promises coming due or already past, what is due today, anything on the calendar, and the single thing that most deserves attention. Not an inventory.\n\nIf there is genuinely nothing pressing, say so in one line — and then do the thing a chief of staff does with an empty morning: ask what should go on today's list, or name the one stale project worth picking up. An empty day is a prompt, not a silence.\n\nDELIVERY: send it with send_telegram. A routine's own output is only written to the log — if you do not call the tool, {{owner_name}} receives nothing at all. Send exactly one message, then stop; do not end the turn by asking whether to keep looking.",
9
9
  "anchor": true
10
10
  },
11
11
  "allowed_tools": [
@@ -0,0 +1,124 @@
1
+ ---
2
+ name: apx-commitment
3
+ description: Promises made to a named person — counterparty, the date you gave them, the channel you said it on. Sibling of apx-task, deliberately NOT the same thing. Load whenever someone else is waiting on something. Triggers: 'I told X I would…', 'le dije a X que…', 'I promised…', 'quedé en…', 'me comprometí a…', 'what do I owe X', 'qué le debo a X', 'overdue promises', 'mark it kept', 'push the date'.
4
+ ---
5
+
6
+ # apx-commitment
7
+
8
+ A `task` is something to do. A `commitment` is something **promised to a specific person**: it has a counterparty, a date you gave them, and the channel you said it on. Breaking one costs trust, not throughput.
9
+
10
+ Append-only JSONL per month at `~/.apx/projects/<apxId>/commitments/YYYY-MM.jsonl`, folded the same way as tasks. Nothing is ever deleted.
11
+
12
+ ## When it is a commitment and not a task
13
+
14
+ The test is one question: **is a named person waiting?**
15
+
16
+ | What was said | Which | Why |
17
+ |---|---|---|
18
+ | "I have to send the quote" | task | Nobody is named. |
19
+ | "I told Ana I'd send her the quote Friday" | commitment | Ana is waiting, and Friday is a date you gave her. |
20
+ | "we should refactor the parser" | task | Internal work. |
21
+ | "I promised the client a demo next week" | commitment | The client will notice if it slips. |
22
+ | "remind me to review the PR" | task | A reminder to yourself. |
23
+ | "I said I'd get back to Bruno today" | commitment | Bruno is expecting it. |
24
+
25
+ Undated is still a commitment. "I promised Ana the quote, no date yet" → record it with no `due`. Refusing to record it because a date is missing means the promise goes unrecorded, which is strictly worse.
26
+
27
+ ## Catching them in conversation
28
+
29
+ This is the main way they get recorded — nobody opens a form to log a promise. Listen for a name plus an obligation, in either language:
30
+
31
+ - "le dije a Ana que el viernes le mando el presupuesto"
32
+ - "quedé en pasarle el informe a Bruno"
33
+ - "me comprometí con el cliente a tener la demo el 10"
34
+ - "I told the team I'd have the migration plan by Thursday"
35
+
36
+ Record it and say in ONE line what you filed and for whom. Do not ask permission to record something you clearly heard — asking makes recording cost more than not recording, and then nothing gets recorded.
37
+
38
+ Resolve a loose date to a real one ("Friday" → that date) and say which date you used, so a wrong guess is visible and correctable.
39
+
40
+ ## Super-agent tools
41
+
42
+ `record_commitment` and `list_commitments`. Both are in the base set — a promise is caught mid-sentence, so they are always loaded.
43
+
44
+ ```json
45
+ { "name": "record_commitment",
46
+ "arguments": { "project": "iacrmar", "counterparty": "Ana",
47
+ "body": "send the revised quote", "due": "2026-05-30",
48
+ "origin_channel": "telegram" } }
49
+ ```
50
+
51
+ `list_commitments` searches **every project** unless you pass one. Omit `project` for "what do I owe people" — that question does not respect a repo boundary.
52
+
53
+ ```json
54
+ { "name": "list_commitments", "arguments": { "overdue": true } }
55
+ { "name": "list_commitments", "arguments": { "counterparty": "ana" } }
56
+ ```
57
+
58
+ Counterparty matching is case-insensitive substring, so `"ana"` finds "Ana Pérez". It is free text, not a contact record — write the name the way the owner says it.
59
+
60
+ ## Concrete CLI calls
61
+
62
+ ```bash
63
+ # Record
64
+ apx commitment add "send the revised quote" --to "Ana" --due 2026-05-30 --project iacrmar
65
+ apx commitment add "the deck for the board" --to "Bruno" --project iacrmar # no date yet
66
+
67
+ # Read
68
+ apx commitment list --all # every project, soonest deadline first
69
+ apx commitment list --all --overdue # what you owe and already missed
70
+ apx commitment list --to Ana --state all # everything ever promised to her
71
+ apx commitment show c_abc123 --project iacrmar
72
+
73
+ # Close it out
74
+ apx commitment kept c_abc123 --project iacrmar
75
+ apx commitment missed c_abc123 --project iacrmar --note "forgot entirely"
76
+ apx commitment renegotiate c_abc123 --due 2026-06-15 --project iacrmar --note "agreed on the call"
77
+ ```
78
+
79
+ ## The three ways one ends
80
+
81
+ | Verb | Means | State after |
82
+ |---|---|---|
83
+ | `kept` | Delivered. | `kept` |
84
+ | `missed` | The date passed and it did not happen. | `missed` |
85
+ | `renegotiate` | A NEW date, agreed with them. | back to `open` |
86
+
87
+ **`renegotiate` reopens rather than closing.** A promise with a new date is a live promise, and every date it has ever had stays in `history`. Moving a date twice is a fact about the relationship; it is only visible because the log keeps it.
88
+
89
+ **`missed` records, it does not hide.** A system that quietly drops what you failed to do cannot tell you that you keep failing the same person.
90
+
91
+ Never mark `kept` on the owner's behalf. If a commitment came due, ASK whether it was kept — you cannot see whether the email was sent.
92
+
93
+ ## Where they show up on their own
94
+
95
+ - **The morning anchor leads with them.** Overdue promises go first, named as a promise to a person, never folded into the task list.
96
+ - **`overdue_commitment` is a CRITICAL signal** (`core/routines/signals.js`), the only detector at that severity. It is the one thing allowed to cross a spent interruption budget.
97
+ - **`commitment_due` fires inside the lead window** (default 48h) — a warning that arrives in time is worth more than one that arrives after.
98
+
99
+ ## ID format
100
+
101
+ `c_` + 6 base36 chars. Prefix matching at ≥3 chars when unique, same as tasks.
102
+
103
+ ## Endpoint surface
104
+
105
+ ```
106
+ GET /api/commitments cross-project; ?state=open|kept|missed|all
107
+ &counterparty=X&overdue=1&due_before=ISO
108
+ &sort=due|newest&limit=N&offset=N
109
+ GET /api/projects/:pid/commitments same filters, one project
110
+ POST /api/projects/:pid/commitments { counterparty, body, due?, origin_channel?, … }
111
+ GET /api/projects/:pid/commitments/:id
112
+ PATCH /api/projects/:pid/commitments/:id { patch: {...} }
113
+ POST /api/projects/:pid/commitments/:id/kept { note? }
114
+ POST /api/projects/:pid/commitments/:id/missed { note? }
115
+ POST /api/projects/:pid/commitments/:id/renegotiate { due, note? }
116
+ GET /api/projects/:pid/commitments-summary → { open, kept, missed, overdue, total }
117
+ ```
118
+
119
+ ## Don't
120
+
121
+ - **Don't record a task as a commitment to make it feel urgent.** The whole value is that a commitment means someone is waiting. Inflate the type and the morning anchor becomes noise.
122
+ - **Don't use tags on tasks for this.** It was considered and rejected: the day you want "everything I owe Ana" you would be substring-matching titles, and `kept` vs `renegotiated` — the distinction that tells you whether a relationship is fine — has nowhere to live.
123
+ - **Don't invent a counterparty.** If you genuinely cannot tell who is waiting, it is a task.
124
+ - **Don't renegotiate without a date.** The CLI refuses it: a promise with no new date is a promise that vanished.