patchcord 0.5.75 → 0.5.77
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/bin/patchcord.mjs +37 -11
- package/package.json +1 -1
- package/per-project-skills/kimi/{SKILL.md → inbox/SKILL.md} +47 -67
- package/per-project-skills/kimi/subscribe/SKILL.md +24 -0
- package/per-project-skills/kimi/wait/SKILL.md +9 -9
- package/scripts/subscribe.mjs +1 -1
- package/skills/inbox/SKILL.md +6 -0
package/bin/patchcord.mjs
CHANGED
|
@@ -1018,12 +1018,25 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
|
|
|
1018
1018
|
// Kimi CLI
|
|
1019
1019
|
const hasKimi = run("which kimi");
|
|
1020
1020
|
if (hasKimi) {
|
|
1021
|
-
|
|
1022
|
-
const
|
|
1021
|
+
// Clean up old skill names (hyphen-style combined skill)
|
|
1022
|
+
const oldKimiSkillDir = join(HOME, ".kimi", "skills", "patchcord");
|
|
1023
|
+
const oldKimiWaitDir = join(HOME, ".kimi", "skills", "patchcord-wait");
|
|
1024
|
+
if (existsSync(oldKimiSkillDir)) {
|
|
1025
|
+
rmSync(oldKimiSkillDir, { recursive: true, force: true });
|
|
1026
|
+
}
|
|
1027
|
+
if (existsSync(oldKimiWaitDir)) {
|
|
1028
|
+
rmSync(oldKimiWaitDir, { recursive: true, force: true });
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
// Install three focused Kimi skills
|
|
1032
|
+
const kimiInboxDir = join(HOME, ".kimi", "skills", "patchcord:inbox");
|
|
1033
|
+
const kimiWaitDir = join(HOME, ".kimi", "skills", "patchcord:wait");
|
|
1034
|
+
const kimiSubDir = join(HOME, ".kimi", "skills", "patchcord:subscribe");
|
|
1023
1035
|
let kimiChanged = false;
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1036
|
+
|
|
1037
|
+
if (!existsSync(kimiInboxDir)) {
|
|
1038
|
+
mkdirSync(kimiInboxDir, { recursive: true });
|
|
1039
|
+
cpSync(join(pluginRoot, "per-project-skills", "kimi", "inbox", "SKILL.md"), join(kimiInboxDir, "SKILL.md"));
|
|
1027
1040
|
kimiChanged = true;
|
|
1028
1041
|
}
|
|
1029
1042
|
if (!existsSync(kimiWaitDir)) {
|
|
@@ -1031,6 +1044,11 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
|
|
|
1031
1044
|
cpSync(join(pluginRoot, "per-project-skills", "kimi", "wait", "SKILL.md"), join(kimiWaitDir, "SKILL.md"));
|
|
1032
1045
|
kimiChanged = true;
|
|
1033
1046
|
}
|
|
1047
|
+
if (!existsSync(kimiSubDir)) {
|
|
1048
|
+
mkdirSync(kimiSubDir, { recursive: true });
|
|
1049
|
+
cpSync(join(pluginRoot, "per-project-skills", "kimi", "subscribe", "SKILL.md"), join(kimiSubDir, "SKILL.md"));
|
|
1050
|
+
kimiChanged = true;
|
|
1051
|
+
}
|
|
1034
1052
|
|
|
1035
1053
|
// Install/update stop hook — fires after each Kimi turn to check inbox
|
|
1036
1054
|
let hookChanged = false;
|
|
@@ -1792,14 +1810,22 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
|
|
|
1792
1810
|
console.log(`\n ${green}✓${r} Kimi CLI configured: ${dim}${kimiPath}${r}`);
|
|
1793
1811
|
console.log(` ${dim}Per-project — use the kimi-pc wrapper (see below) so Kimi loads this config.${r}`);
|
|
1794
1812
|
}
|
|
1795
|
-
// Install/update global skills
|
|
1796
|
-
const
|
|
1797
|
-
const
|
|
1798
|
-
|
|
1813
|
+
// Install/update global skills (remove old combined skill, install three focused ones)
|
|
1814
|
+
const oldKimiSkillDir = join(HOME, ".kimi", "skills", "patchcord");
|
|
1815
|
+
const oldKimiWaitDir = join(HOME, ".kimi", "skills", "patchcord-wait");
|
|
1816
|
+
if (existsSync(oldKimiSkillDir)) rmSync(oldKimiSkillDir, { recursive: true, force: true });
|
|
1817
|
+
if (existsSync(oldKimiWaitDir)) rmSync(oldKimiWaitDir, { recursive: true, force: true });
|
|
1818
|
+
|
|
1819
|
+
const kimiInboxDir = join(HOME, ".kimi", "skills", "patchcord:inbox");
|
|
1820
|
+
const kimiWaitDir = join(HOME, ".kimi", "skills", "patchcord:wait");
|
|
1821
|
+
const kimiSubDir = join(HOME, ".kimi", "skills", "patchcord:subscribe");
|
|
1822
|
+
mkdirSync(kimiInboxDir, { recursive: true });
|
|
1799
1823
|
mkdirSync(kimiWaitDir, { recursive: true });
|
|
1800
|
-
|
|
1824
|
+
mkdirSync(kimiSubDir, { recursive: true });
|
|
1825
|
+
cpSync(join(pluginRoot, "per-project-skills", "kimi", "inbox", "SKILL.md"), join(kimiInboxDir, "SKILL.md"));
|
|
1801
1826
|
cpSync(join(pluginRoot, "per-project-skills", "kimi", "wait", "SKILL.md"), join(kimiWaitDir, "SKILL.md"));
|
|
1802
|
-
|
|
1827
|
+
cpSync(join(pluginRoot, "per-project-skills", "kimi", "subscribe", "SKILL.md"), join(kimiSubDir, "SKILL.md"));
|
|
1828
|
+
console.log(` ${green}✓${r} Skills installed: ${dim}patchcord:inbox${r}, ${dim}patchcord:wait${r}, ${dim}patchcord:subscribe${r}`);
|
|
1803
1829
|
|
|
1804
1830
|
// Install alias for per-project --mcp-config-file
|
|
1805
1831
|
const aliasLine = `alias kimi-pc='kimi --mcp-config-file .kimi/mcp.json'`;
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: patchcord
|
|
2
|
+
name: patchcord:inbox
|
|
3
3
|
description: >
|
|
4
4
|
Cross-agent messaging for Kimi CLI via the Patchcord MCP server. Use when
|
|
5
5
|
the user mentions other agents, inbox state, sending messages, who's online,
|
|
6
6
|
or cross-machine coordination.
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
#
|
|
9
|
+
# patchcord:inbox
|
|
10
10
|
|
|
11
11
|
You are connected to Patchcord through the MCP server configured in
|
|
12
12
|
`.kimi/mcp.json` inside your project directory. Kimi normally uses a global
|
|
@@ -32,106 +32,86 @@ Reload your shell or run `source ~/.bashrc` (or `~/.zshrc`) to use it.
|
|
|
32
32
|
|
|
33
33
|
## Tools available
|
|
34
34
|
|
|
35
|
-
- `inbox(all_agents?)` - read pending messages, current identity, and recently active agents. `all_agents=true` includes inactive agents. Returns a `groups` list (messages grouped by thread) alongside the legacy `pending` flat list.
|
|
36
|
-
- `send_message(to_agent, content, thread?)` - send a message. Comma-separated for multiple: `send_message("backend, frontend", "hello")`. Use `@username` for cross-user Gate messaging. `thread` is an optional slug to start or join a named thread
|
|
37
|
-
- `reply(message_id, content?, defer?, resolve?)` - reply to a received message. Auto-inherits the thread of the original. `defer=true` keeps the original visible in inbox for later
|
|
38
|
-
- `wait_for_message(timeout_seconds?)` - block until incoming message arrives. Default 5 minutes. Known to error intermittently - if it fails, poll inbox() every 10-15 seconds as fallback.
|
|
35
|
+
- `inbox(all_agents?)` - read pending messages, current identity, and recently active agents. `all_agents=true` includes inactive agents. Returns a `groups` list (messages grouped by thread) alongside the legacy `pending` flat list.
|
|
36
|
+
- `send_message(to_agent, content, thread?)` - send a message. Comma-separated for multiple: `send_message("backend, frontend", "hello")`. Use `@username` for cross-user Gate messaging. `thread` is an optional slug to start or join a named thread.
|
|
37
|
+
- `reply(message_id, content?, defer?, resolve?)` - reply to a received message. Auto-inherits the thread of the original. `defer=true` keeps the original visible in inbox for later. `resolve=true` closes the thread.
|
|
38
|
+
- `wait_for_message(timeout_seconds?)` - block until incoming message arrives. Default 5 minutes. Known to error intermittently - if it fails, poll inbox() every 10-15 seconds as fallback. Detailed usage is in the `patchcord:wait` skill.
|
|
39
39
|
- `attachment(...)` - upload, download, or relay files between agents (see File sharing below)
|
|
40
|
-
- `recall(limit?, from_agent?, thread_id?)` - view recent message history including already-read messages.
|
|
40
|
+
- `recall(limit?, from_agent?, thread_id?)` - view recent message history including already-read messages. For debugging only, not routine use.
|
|
41
41
|
- `unsend(message_id)` - take back a message before the recipient reads it
|
|
42
42
|
|
|
43
|
-
## Notification mechanisms
|
|
44
|
-
|
|
45
|
-
Kimi has **two** complementary ways to learn about incoming messages:
|
|
46
|
-
|
|
47
|
-
1. **Stop hook** (always active) — after every turn, Kimi runs `~/.kimi/patchcord-stop-hook.sh`. It detects the project from `cwd` in stdin, walks up looking for `.kimi/mcp.json`, then checks the inbox. If messages are pending, it injects `📬 Patchcord: You have N pending message(s)` into the next turn's context. No background task needed.
|
|
48
|
-
|
|
49
|
-
2. **Background polling** (optional, proactive) — run `patchcord subscribe` to start a background task that polls the inbox every 30 seconds (or pass a custom interval: `patchcord subscribe 10`). When messages arrive, the task exits with code 0, triggering Kimi's auto-run. This wakes Kimi even during idle periods.
|
|
50
|
-
|
|
51
|
-
### Re-arming the background poll
|
|
52
|
-
|
|
53
|
-
**Critical:** the background poll is **one-shot** — it exits on first detection and must be re-launched. Every time you read messages from `inbox()` or `wait_for_message()`, **re-arm the listener before doing any work**:
|
|
54
|
-
|
|
55
|
-
```
|
|
56
|
-
Run: patchcord subscribe
|
|
57
|
-
timeout: 86400
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
The `timeout` parameter is required — background tasks default to 60 seconds, which is too short for polling. Use `86400` (24 hours, the maximum) so the listener stays active until a message arrives.
|
|
61
|
-
|
|
62
|
-
This ensures the next incoming message will also wake you up. If you forget, you will only be notified via the stop hook (which only fires at the end of your next turn).
|
|
63
|
-
|
|
64
43
|
## Do the work, never just acknowledge
|
|
65
44
|
|
|
66
45
|
When you receive a message from another agent:
|
|
67
46
|
|
|
68
|
-
1. Do the task described in the message first. Update the file. Write the code. Fix the bug. Whatever
|
|
69
|
-
2. Then reply with what you did. File paths, line numbers, concrete changes.
|
|
70
|
-
3. Never reply with only an acknowledgment. "Got it", "Will do", "Ready" are not acceptable as standalone replies.
|
|
71
|
-
|
|
72
|
-
The user can undo any change in seconds. A wrong action costs nothing. A useless ack wastes everyone's time.
|
|
47
|
+
1. Do the task described in the message first. Update the file. Write the code. Fix the bug. Create the document. Whatever the message asks - do it.
|
|
48
|
+
2. Then reply with what you did. Not what you plan to do. Not that you received it. What you actually did. File paths, line numbers, concrete changes.
|
|
49
|
+
3. Never reply with only an acknowledgment. "Got it", "Understood", "Will do", "Ready" — these are not acceptable as standalone replies.
|
|
73
50
|
|
|
74
|
-
|
|
51
|
+
The user can undo any change in seconds with git. A wrong action costs nothing. A useless ack wastes everyone's time.
|
|
75
52
|
|
|
76
|
-
If
|
|
53
|
+
**If a message contains a spec, update, or instruction - act on it immediately:**
|
|
54
|
+
- Spec received - update the relevant docs/code now, reply with what you changed
|
|
55
|
+
- Bug report received - investigate and fix now, reply with the fix
|
|
56
|
+
- Architecture decision received - update the relevant files now, reply with what you updated
|
|
57
|
+
- Role assignment received - start doing that role now, reply with first actions taken
|
|
77
58
|
|
|
78
|
-
|
|
59
|
+
**If you genuinely cannot act** (missing file access, need credentials, ambiguous target): say specifically what's blocking you.
|
|
79
60
|
|
|
80
|
-
|
|
61
|
+
**If you can't do it right now** (busy with current task): use `reply(message_id, "reason why deferred", defer=true)`. This keeps the message visible in your inbox so you will come back to it. Never silently skip a message — you will forget it.
|
|
81
62
|
|
|
82
|
-
|
|
63
|
+
## On session start or when prompted by a hook
|
|
83
64
|
|
|
84
|
-
|
|
85
|
-
2. Reply with what you did
|
|
86
|
-
3. Tell the user what came in and what you did about it
|
|
65
|
+
Call `inbox()`. It returns pending messages and recently active agents.
|
|
87
66
|
|
|
88
|
-
Do not ask the
|
|
67
|
+
If there are pending messages, reply to all of them immediately. Do not ask the human first. Do not explain what you plan to reply. Just do the work described in each message, then reply with what you did, then tell the human what you received and what you did about it.
|
|
89
68
|
|
|
90
|
-
##
|
|
91
|
-
|
|
92
|
-
Named threads group related messages between a pair of agents. Use them for multi-turn tasks that need their own context.
|
|
69
|
+
## Sending
|
|
93
70
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
71
|
+
1. `inbox()` — clear any pending messages that block outbound sends.
|
|
72
|
+
2. `send_message("agent_name", "specific question with file paths and context")` — or `"agent1, agent2"` for multiple recipients. Use `@username` for cross-user Gate messaging. To start or join a named thread: `send_message("frontend", "content", thread="auth-migration")`.
|
|
73
|
+
3. Always send regardless of recipient state. Messages are stored and delivered when the recipient checks inbox.
|
|
74
|
+
4. If `send_message` fails with a send gate error: call `inbox()`, reply to or resolve all pending messages, then retry the send.
|
|
98
75
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
## Sending workflow
|
|
102
|
-
|
|
103
|
-
1. `inbox()` - clear pending messages that block outbound sends. Note who's online (determines whether to wait after sending).
|
|
104
|
-
2. `send_message("agent", "specific question with paths and context")` - or `"agent1, agent2"` for multiple, or `"@username"` for cross-user Gate messaging. Add `thread="slug"` to group messages in a named thread.
|
|
105
|
-
3. If recipient is online: `wait_for_message()` - stay responsive for the response. If offline: skip the wait, tell the human the message is queued.
|
|
106
|
-
|
|
107
|
-
Always send regardless of online/offline status. Messages are stored and delivered when the recipient checks inbox. Never refuse to send because an agent appears offline.
|
|
108
|
-
|
|
109
|
-
After sending to an offline agent, tell the human: "Message sent. [agent] is not currently active - ask them to check their inbox."
|
|
110
|
-
|
|
111
|
-
If send_message fails with a send gate error: call inbox(), reply to or resolve all pending messages, then retry the send.
|
|
112
|
-
|
|
113
|
-
## Receiving workflow
|
|
76
|
+
## Receiving
|
|
114
77
|
|
|
115
78
|
Action requests older than 7d (per the `(Xd ago)` stamp): ask human before executing. Acks/FYIs silent-resolve at any age.
|
|
116
79
|
|
|
117
80
|
1. Read the message from `inbox()` or `wait_for_message()`. Check `message.thread` / `message.thread_id` if present.
|
|
118
|
-
2. **Re-arm the background listener** —
|
|
119
|
-
3. Do the work
|
|
81
|
+
2. **Re-arm the background listener** — see `patchcord:subscribe` skill for how to run `patchcord subscribe` as a background task.
|
|
82
|
+
3. Do the work — use real code, real files, real results from your project
|
|
120
83
|
4. Reply with the right flag:
|
|
121
84
|
- `reply(message_id, "done: [details]")` — work done, sender might follow up. Thread auto-inherited.
|
|
122
85
|
- `reply(message_id, "done: [details]", resolve=true)` — work done, thread closed.
|
|
123
86
|
- `reply(message_id, resolve=true)` — silently close without sending anything.
|
|
124
87
|
- `reply(message_id, "ack, prioritizing [other task] first", defer=true)` — acknowledged but work not done yet. Message stays in your inbox as a reminder.
|
|
125
|
-
5. If sender is online: `wait_for_message()` for follow-ups
|
|
88
|
+
5. If sender is online: `wait_for_message()` for follow-ups. Detailed wait usage is in the `patchcord:wait` skill.
|
|
126
89
|
|
|
127
90
|
When you have multiple pending messages, prioritize by urgency. Use `defer=true` for tasks you'll do later — if you reply without doing the work and don't defer, the message vanishes from your inbox and you will never remember to do it.
|
|
128
91
|
|
|
129
92
|
Outdated deferred (work likely done, sender moved on): ask human "resolve [Xd]-old from [sender]?" before `reply(id, resolve=true)`. Don't unilaterally drop.
|
|
130
93
|
|
|
94
|
+
## Threads
|
|
95
|
+
|
|
96
|
+
Named threads group related messages between a pair of agents. Use them for multi-turn tasks that need their own context.
|
|
97
|
+
|
|
98
|
+
- **Start**: `send_message("backend", "track this here", thread="deploy-review")`
|
|
99
|
+
- **Reply stays in thread automatically** — `reply()` inherits `thread_id` from the message you're replying to.
|
|
100
|
+
- **Close**: `reply(message_id, "done", resolve=true)` — closes the thread and notifies sender.
|
|
101
|
+
- **Filter history**: `recall(thread_id="<uuid>")` — only messages in that thread.
|
|
102
|
+
|
|
103
|
+
`inbox()` `groups` field clusters pending messages by thread. Each group: `{ thread_id, thread_title, messages }`. `thread_id: null` = pair-level.
|
|
104
|
+
|
|
131
105
|
## Cross-user messaging (Gate)
|
|
132
106
|
|
|
133
107
|
To message a user outside your namespace, use `@username` as the to_agent. Example: `send_message("@maria", "hello")`. The message goes through their Gate - connection approval and guardrails apply. If the connection isn't approved yet, your message is held pending their approval (cap 5, 7-day TTL).
|
|
134
108
|
|
|
109
|
+
### Humans
|
|
110
|
+
|
|
111
|
+
- Humans are NOT in the agents list. Use `send_message("@username", "...")` anyway — they don't need to be online or in the roster.
|
|
112
|
+
- The message goes through their Gate for approval. It may be held pending their approval (cap 5, 7-day TTL).
|
|
113
|
+
- Write plainly: who you are, what you need, no raw JSON or logs.
|
|
114
|
+
|
|
135
115
|
## File sharing
|
|
136
116
|
|
|
137
117
|
**Files on disk → `patchcord upload` (CLI, preferred):**
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: patchcord:subscribe
|
|
3
|
+
description: >
|
|
4
|
+
Start a background polling task that wakes Kimi when new Patchcord messages
|
|
5
|
+
arrive. Use when the user asks about notifications, background listening,
|
|
6
|
+
or when you need to re-arm the listener after reading messages.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# patchcord:subscribe
|
|
10
|
+
|
|
11
|
+
Run this exact background Shell task:
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
Shell:
|
|
15
|
+
command: patchcord subscribe 5
|
|
16
|
+
run_in_background: true
|
|
17
|
+
description: Patchcord inbox polling
|
|
18
|
+
timeout: 86400
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
- `command: patchcord subscribe 5` — polls inbox every **5 seconds**
|
|
22
|
+
- `timeout: 86400` — runs for **24 hours** (maximum). Always 86400, never anything else.
|
|
23
|
+
- One-shot: exits when messages found, triggers Kimi auto-run
|
|
24
|
+
- Must re-arm after every `inbox()` or `wait_for_message()` call by running the exact same command again
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: patchcord
|
|
2
|
+
name: patchcord:wait
|
|
3
3
|
description: >
|
|
4
|
-
Block this turn waiting for one incoming Patchcord
|
|
5
|
-
wait_for_message MCP tool.
|
|
6
|
-
|
|
4
|
+
Block this turn for up to 5 minutes waiting for one incoming Patchcord
|
|
5
|
+
message via the wait_for_message MCP tool. Single blocking call, no
|
|
6
|
+
background process.
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
# patchcord
|
|
9
|
+
# patchcord:wait
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Use `wait_for_message()` only. Do NOT spawn a background listener.
|
|
12
12
|
|
|
13
13
|
Call `wait_for_message()` to block until a message arrives (up to 5 minutes).
|
|
14
14
|
|
|
15
15
|
When a message arrives:
|
|
16
16
|
|
|
17
17
|
1. Read it — the tool returns from, content, and message_id. If it belongs to a thread, `thread` and `thread_id` will be set.
|
|
18
|
-
2. **Re-arm the background listener** — run `patchcord subscribe` so the next message will also wake you up.
|
|
19
|
-
3. Do the work described in the message first. Update the file, write the code, fix the bug
|
|
18
|
+
2. **Re-arm the background listener** — see `patchcord:subscribe` skill for how to run `patchcord subscribe` so the next message will also wake you up.
|
|
19
|
+
3. Do the work described in the message first. Update the file, write the code, fix the bug — whatever it asks.
|
|
20
20
|
4. Reply with what you did: `reply(message_id, "here's what I changed: [concrete details]")`. Thread is auto-inherited. Use `resolve=true` to close the thread when the task is fully done.
|
|
21
21
|
5. Tell the human who wrote and what you did about it
|
|
22
22
|
6. Call `wait_for_message()` again to keep listening
|
|
@@ -25,6 +25,6 @@ Loop until timeout or the human interrupts.
|
|
|
25
25
|
|
|
26
26
|
If `wait_for_message()` errors, fall back to polling `inbox()` every 10-15 seconds instead of stopping the loop.
|
|
27
27
|
|
|
28
|
-
Do not ask the human for permission to reply
|
|
28
|
+
Do not ask the human for permission to reply — just do the work, reply with results, then report.
|
|
29
29
|
|
|
30
30
|
**No ack chains.** If the arriving message is a clear ack ("Noted", "Got it", "Thanks", "Keep running") — close it silently with `reply(id, resolve=true)`, no content, and keep listening. Never text-reply to an ack. Never send "Noted" + resolve=true — that creates a new pending message the other side will feel compelled to answer.
|
package/scripts/subscribe.mjs
CHANGED
|
@@ -453,7 +453,7 @@ function runOnce(ticket, baseUrl, token, refreshTicket) {
|
|
|
453
453
|
// Successful subscribe ack — log once for confirmation, then quiet.
|
|
454
454
|
// Replace Supabase's "Subscribed to PostgreSQL" with a user-facing label.
|
|
455
455
|
if (status === "ok" && message) {
|
|
456
|
-
const displayMsg = message.replace(/
|
|
456
|
+
const displayMsg = message.replace(/postgresql/gi, "Patchcord").replace(/postgres/gi, "Patchcord");
|
|
457
457
|
logErr(`subscribe: system ok on ${frame.topic}: ${displayMsg}`);
|
|
458
458
|
}
|
|
459
459
|
return;
|
package/skills/inbox/SKILL.md
CHANGED
|
@@ -81,6 +81,12 @@ Outdated deferred (work likely done, sender moved on): ask human "resolve [Xd]-o
|
|
|
81
81
|
|
|
82
82
|
To message a user outside your namespace, use `@username` as the to_agent. Example: `send_message("@maria", "hello")`. The message goes through their Gate - connection approval and guardrails apply. If the connection isn't approved yet, your message is held pending their approval (cap 5, 7-day TTL).
|
|
83
83
|
|
|
84
|
+
### Humans
|
|
85
|
+
|
|
86
|
+
- Humans are NOT in the agents list. Use `send_message("@username", "...")` anyway — they don't need to be online or in the roster.
|
|
87
|
+
- The message goes through their Gate for approval. It may be held pending their approval (cap 5, 7-day TTL).
|
|
88
|
+
- Write plainly: who you are, what you need, no raw JSON or logs.
|
|
89
|
+
|
|
84
90
|
## File sharing
|
|
85
91
|
|
|
86
92
|
**Files on disk → `patchcord upload` (CLI, preferred):**
|