u-foo 1.0.3 → 1.1.9

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 (179) hide show
  1. package/README.md +110 -11
  2. package/README.zh-CN.md +9 -7
  3. package/SKILLS/ufoo/SKILL.md +132 -0
  4. package/SKILLS/uinit/SKILL.md +78 -0
  5. package/SKILLS/ustatus/SKILL.md +36 -0
  6. package/bin/uclaude.js +13 -0
  7. package/bin/ucode-core.js +15 -0
  8. package/bin/ucode.js +125 -0
  9. package/bin/ucodex.js +13 -0
  10. package/bin/ufoo +9 -31
  11. package/bin/ufoo-assistant-agent.js +5 -0
  12. package/bin/ufoo-engine.js +25 -0
  13. package/bin/ufoo.js +17 -0
  14. package/modules/AGENTS.template.md +29 -11
  15. package/modules/bus/README.md +33 -25
  16. package/modules/bus/SKILLS/ubus/SKILL.md +19 -8
  17. package/modules/context/README.md +18 -40
  18. package/modules/context/SKILLS/uctx/SKILL.md +63 -1
  19. package/modules/online/SKILLS/ufoo-online/SKILL.md +144 -0
  20. package/package.json +25 -4
  21. package/scripts/import-pi-mono.js +124 -0
  22. package/scripts/postinstall.js +30 -0
  23. package/scripts/sync-claude-skills.sh +21 -0
  24. package/src/agent/cliRunner.js +554 -33
  25. package/src/agent/internalRunner.js +150 -56
  26. package/src/agent/launcher.js +754 -0
  27. package/src/agent/normalizeOutput.js +1 -1
  28. package/src/agent/notifier.js +340 -0
  29. package/src/agent/ptyRunner.js +847 -0
  30. package/src/agent/ptyWrapper.js +379 -0
  31. package/src/agent/readyDetector.js +175 -0
  32. package/src/agent/ucode.js +443 -0
  33. package/src/agent/ucodeBootstrap.js +113 -0
  34. package/src/agent/ucodeBuild.js +67 -0
  35. package/src/agent/ucodeDoctor.js +184 -0
  36. package/src/agent/ucodeRuntimeConfig.js +129 -0
  37. package/src/agent/ufooAgent.js +46 -42
  38. package/src/assistant/agent.js +260 -0
  39. package/src/assistant/bridge.js +172 -0
  40. package/src/assistant/engine.js +252 -0
  41. package/src/assistant/stdio.js +58 -0
  42. package/src/assistant/ufooEngineCli.js +306 -0
  43. package/src/bus/activate.js +172 -0
  44. package/src/bus/daemon.js +436 -0
  45. package/src/bus/index.js +842 -0
  46. package/src/bus/inject.js +315 -0
  47. package/src/bus/message.js +430 -0
  48. package/src/bus/nickname.js +88 -0
  49. package/src/bus/queue.js +136 -0
  50. package/src/bus/shake.js +26 -0
  51. package/src/bus/store.js +189 -0
  52. package/src/bus/subscriber.js +312 -0
  53. package/src/bus/utils.js +363 -0
  54. package/src/chat/agentBar.js +117 -0
  55. package/src/chat/agentDirectory.js +88 -0
  56. package/src/chat/agentSockets.js +225 -0
  57. package/src/chat/agentViewController.js +298 -0
  58. package/src/chat/chatLogController.js +115 -0
  59. package/src/chat/commandExecutor.js +700 -0
  60. package/src/chat/commands.js +132 -0
  61. package/src/chat/completionController.js +414 -0
  62. package/src/chat/cronScheduler.js +160 -0
  63. package/src/chat/daemonConnection.js +166 -0
  64. package/src/chat/daemonCoordinator.js +64 -0
  65. package/src/chat/daemonMessageRouter.js +257 -0
  66. package/src/chat/daemonReconnect.js +41 -0
  67. package/src/chat/daemonTransport.js +36 -0
  68. package/src/chat/daemonTransportDefaults.js +10 -0
  69. package/src/chat/dashboardKeyController.js +480 -0
  70. package/src/chat/dashboardView.js +154 -0
  71. package/src/chat/index.js +1011 -1392
  72. package/src/chat/inputHistoryController.js +105 -0
  73. package/src/chat/inputListenerController.js +304 -0
  74. package/src/chat/inputMath.js +104 -0
  75. package/src/chat/inputSubmitHandler.js +171 -0
  76. package/src/chat/layout.js +165 -0
  77. package/src/chat/pasteController.js +81 -0
  78. package/src/chat/rawKeyMap.js +42 -0
  79. package/src/chat/settingsController.js +132 -0
  80. package/src/chat/statusLineController.js +177 -0
  81. package/src/chat/streamTracker.js +138 -0
  82. package/src/chat/text.js +70 -0
  83. package/src/chat/transport.js +61 -0
  84. package/src/cli/busCoreCommands.js +59 -0
  85. package/src/cli/ctxCoreCommands.js +199 -0
  86. package/src/cli/onlineCoreCommands.js +379 -0
  87. package/src/cli.js +1162 -96
  88. package/src/code/README.md +29 -0
  89. package/src/code/UCODE_PROMPT.md +32 -0
  90. package/src/code/agent.js +1651 -0
  91. package/src/code/cli.js +158 -0
  92. package/src/code/config +0 -0
  93. package/src/code/dispatch.js +42 -0
  94. package/src/code/index.js +70 -0
  95. package/src/code/nativeRunner.js +1213 -0
  96. package/src/code/runtime.js +154 -0
  97. package/src/code/sessionStore.js +162 -0
  98. package/src/code/taskDecomposer.js +269 -0
  99. package/src/code/tools/bash.js +53 -0
  100. package/src/code/tools/common.js +42 -0
  101. package/src/code/tools/edit.js +70 -0
  102. package/src/code/tools/read.js +44 -0
  103. package/src/code/tools/write.js +35 -0
  104. package/src/code/tui.js +1580 -0
  105. package/src/config.js +56 -3
  106. package/src/context/decisions.js +324 -0
  107. package/src/context/doctor.js +183 -0
  108. package/src/context/index.js +55 -0
  109. package/src/context/sync.js +127 -0
  110. package/src/daemon/agentProcessManager.js +74 -0
  111. package/src/daemon/cronOps.js +241 -0
  112. package/src/daemon/index.js +998 -170
  113. package/src/daemon/ipcServer.js +99 -0
  114. package/src/daemon/ops.js +630 -48
  115. package/src/daemon/promptLoop.js +319 -0
  116. package/src/daemon/promptRequest.js +101 -0
  117. package/src/daemon/providerSessions.js +306 -0
  118. package/src/daemon/reporting.js +90 -0
  119. package/src/daemon/run.js +31 -1
  120. package/src/daemon/status.js +48 -8
  121. package/src/doctor/index.js +50 -0
  122. package/src/init/index.js +318 -0
  123. package/src/online/bridge.js +663 -0
  124. package/src/online/client.js +245 -0
  125. package/src/online/runner.js +253 -0
  126. package/src/online/server.js +992 -0
  127. package/src/online/tokens.js +103 -0
  128. package/src/report/store.js +331 -0
  129. package/src/shared/eventContract.js +35 -0
  130. package/src/shared/ptySocketContract.js +21 -0
  131. package/src/skills/index.js +159 -0
  132. package/src/status/index.js +285 -0
  133. package/src/terminal/adapterContract.js +87 -0
  134. package/src/terminal/adapterRouter.js +84 -0
  135. package/src/terminal/adapters/externalAdapter.js +14 -0
  136. package/src/terminal/adapters/internalAdapter.js +13 -0
  137. package/src/terminal/adapters/internalPtyAdapter.js +42 -0
  138. package/src/terminal/adapters/internalQueueAdapter.js +37 -0
  139. package/src/terminal/adapters/terminalAdapter.js +31 -0
  140. package/src/terminal/adapters/tmuxAdapter.js +30 -0
  141. package/src/terminal/detect.js +64 -0
  142. package/src/terminal/index.js +8 -0
  143. package/src/terminal/iterm2.js +126 -0
  144. package/src/ufoo/agentsStore.js +107 -0
  145. package/src/ufoo/paths.js +46 -0
  146. package/src/utils/banner.js +76 -0
  147. package/bin/uclaude +0 -65
  148. package/bin/ucodex +0 -65
  149. package/modules/bus/scripts/bus-alert.sh +0 -185
  150. package/modules/bus/scripts/bus-listen.sh +0 -117
  151. package/modules/context/ASSUMPTIONS.md +0 -7
  152. package/modules/context/CONSTRAINTS.md +0 -7
  153. package/modules/context/CONTEXT-STRUCTURE.md +0 -49
  154. package/modules/context/DECISION-PROTOCOL.md +0 -62
  155. package/modules/context/HANDOFF.md +0 -33
  156. package/modules/context/RULES.md +0 -15
  157. package/modules/context/SKILLS/README.md +0 -14
  158. package/modules/context/SYSTEM.md +0 -18
  159. package/modules/context/TEMPLATES/assumptions.md +0 -4
  160. package/modules/context/TEMPLATES/constraints.md +0 -4
  161. package/modules/context/TEMPLATES/decision.md +0 -16
  162. package/modules/context/TEMPLATES/project-context-readme.md +0 -6
  163. package/modules/context/TEMPLATES/system.md +0 -3
  164. package/modules/context/TEMPLATES/terminology.md +0 -4
  165. package/modules/context/TERMINOLOGY.md +0 -10
  166. package/scripts/banner.sh +0 -89
  167. package/scripts/bus-alert.sh +0 -6
  168. package/scripts/bus-autotrigger.sh +0 -6
  169. package/scripts/bus-daemon.sh +0 -231
  170. package/scripts/bus-inject.sh +0 -144
  171. package/scripts/bus-listen.sh +0 -6
  172. package/scripts/bus.sh +0 -984
  173. package/scripts/context-decisions.sh +0 -167
  174. package/scripts/context-doctor.sh +0 -72
  175. package/scripts/context-lint.sh +0 -110
  176. package/scripts/doctor.sh +0 -22
  177. package/scripts/init.sh +0 -247
  178. package/scripts/skills.sh +0 -113
  179. package/scripts/status.sh +0 -125
package/bin/ufoo CHANGED
@@ -18,14 +18,14 @@ Usage:
18
18
  ufoo daemon --start|--stop|--status
19
19
  ufoo chat
20
20
  ufoo init [--modules context[,resources]] [--project <dir>]
21
- ufoo bus <...> # delegates to ./scripts/bus.sh in the current project
22
- ufoo ctx <...> # delegates to ./scripts/ai-context-*.sh in the current project
21
+ ufoo bus <...> # JS bus implementation (project-local data)
22
+ ufoo ctx <...> # JS context commands (doctor|lint|decisions)
23
23
  ufoo skills list
24
24
  ufoo skills install <name|all> [--codex|--agents|--target <dir>]
25
25
 
26
26
  Notes:
27
27
  - `init` creates/updates <project>/.ai-context and injects CLAUDE.md/AGENTS.md blocks.
28
- - For Codex notifications, prefer `scripts/bus-alert.sh` / `scripts/bus-listen.sh` (no IME issues).
28
+ - For Codex notifications, prefer `ufoo bus alert` / `ufoo bus listen` (no IME issues).
29
29
  USAGE
30
30
  }
31
31
 
@@ -37,10 +37,10 @@ case "$cmd" in
37
37
  exec node "$repo_root/bin/ufoo.js" chat
38
38
  ;;
39
39
  doctor)
40
- exec bash "$repo_root/scripts/doctor.sh"
40
+ exec node "$repo_root/bin/ufoo.js" doctor "$@"
41
41
  ;;
42
42
  status)
43
- exec bash "$repo_root/scripts/status.sh"
43
+ exec node "$repo_root/bin/ufoo.js" status "$@"
44
44
  ;;
45
45
  daemon)
46
46
  exec node "$repo_root/bin/ufoo.js" daemon "$@"
@@ -49,41 +49,19 @@ case "$cmd" in
49
49
  exec node "$repo_root/bin/ufoo.js" chat
50
50
  ;;
51
51
  init)
52
- exec bash "$repo_root/scripts/init.sh" "$@"
52
+ exec node "$repo_root/bin/ufoo.js" init "$@"
53
53
  ;;
54
54
  bus)
55
55
  # Project-local bus commands. Must be run from within the target project.
56
- if [[ ! -x "./scripts/bus.sh" ]]; then
57
- echo "FAIL: missing ./scripts/bus.sh. Run: ufoo init --modules bus" >&2
58
- exit 1
59
- fi
60
- exec bash "./scripts/bus.sh" "$@"
56
+ exec node "$repo_root/bin/ufoo.js" bus "$@"
61
57
  ;;
62
58
  ctx)
63
- # Project-local ctx commands. Must be run from within the target project.
64
- sub="${1:-doctor}"
65
- shift || true
66
- case "$sub" in
67
- doctor)
68
- exec bash "./scripts/ai-context-doctor.sh" "$@"
69
- ;;
70
- lint)
71
- exec bash "./scripts/ai-context-lint.sh" "$@"
72
- ;;
73
- decisions)
74
- exec bash "./scripts/ai-context-decisions.sh" "$@"
75
- ;;
76
- *)
77
- echo "Unknown ctx subcommand: $sub" >&2
78
- echo "Supported: doctor, lint, decisions" >&2
79
- exit 1
80
- ;;
81
- esac
59
+ exec node "$repo_root/bin/ufoo.js" ctx "$@"
82
60
  ;;
83
61
  skills)
84
62
  sub="${1:-}"
85
63
  shift || true
86
- exec bash "$repo_root/scripts/skills.sh" "$sub" "$@"
64
+ exec node "$repo_root/bin/ufoo.js" skills "$sub" "$@"
87
65
  ;;
88
66
  *)
89
67
  echo "Unknown command: $cmd" >&2
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { runAssistantStdio } = require("../src/assistant/stdio");
4
+
5
+ runAssistantStdio();
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { runUfooEngineCli } = require("../src/assistant/ufooEngineCli");
4
+
5
+ function readStdin() {
6
+ return new Promise((resolve) => {
7
+ let data = "";
8
+ process.stdin.setEncoding("utf8");
9
+ process.stdin.on("data", (chunk) => {
10
+ data += chunk;
11
+ });
12
+ process.stdin.on("end", () => resolve(data));
13
+ process.stdin.resume();
14
+ });
15
+ }
16
+
17
+ (async () => {
18
+ const stdinText = await readStdin();
19
+ const result = await runUfooEngineCli({
20
+ argv: process.argv.slice(2),
21
+ stdinText,
22
+ });
23
+ process.stdout.write(result.output);
24
+ process.exitCode = result.exitCode;
25
+ })();
package/bin/ufoo.js CHANGED
@@ -4,6 +4,7 @@ const { runCli } = require("../src/cli");
4
4
  const { runDaemonCli } = require("../src/daemon/run");
5
5
  const { runChat } = require("../src/chat");
6
6
  const { runInternalRunner } = require("../src/agent/internalRunner");
7
+ const { runPtyRunner } = require("../src/agent/ptyRunner");
7
8
 
8
9
  const cmd = process.argv[2];
9
10
 
@@ -21,6 +22,22 @@ async function main() {
21
22
  await runInternalRunner({ projectRoot: process.cwd(), agentType });
22
23
  return;
23
24
  }
25
+ if (cmd === "agent-pty-runner") {
26
+ const agentType = process.argv[3] || "codex";
27
+ try {
28
+ await runPtyRunner({ projectRoot: process.cwd(), agentType });
29
+ } catch (err) {
30
+ const normalized = String(agentType || "").trim().toLowerCase();
31
+ if (normalized === "ufoo" || normalized === "ucode" || normalized === "ufoo-code") {
32
+ throw err;
33
+ }
34
+ // Fallback to headless runner if PTY is unavailable
35
+ // eslint-disable-next-line no-console
36
+ console.error(`[pty-runner] ${err.message || err}. Falling back to headless internal runner.`);
37
+ await runInternalRunner({ projectRoot: process.cwd(), agentType });
38
+ }
39
+ return;
40
+ }
24
41
  if (cmd === "chat") {
25
42
  await runChat(process.cwd());
26
43
  return;
@@ -27,10 +27,17 @@ ufoo ctx decisions -l # List all decisions
27
27
  ufoo ctx decisions -n 1 # Show latest decision
28
28
 
29
29
  # Bus
30
- ufoo bus join # Join bus (auto by uclaude/ucodex)
30
+ SUBSCRIBER="${UFOO_SUBSCRIBER_ID:-$(ufoo bus whoami 2>/dev/null || true)}"
31
+ [ -n "$SUBSCRIBER" ] || SUBSCRIBER=$(ufoo bus join | tail -1)
31
32
  ufoo bus check $SUBSCRIBER # Check pending messages
32
33
  ufoo bus send "<id>" "<msg>" # Send message
33
34
  ufoo bus status # Show bus status
35
+
36
+ # Runtime report (shared contract for assistant/ucodex/uclaude)
37
+ ufoo report start "<task>" --task <id> --agent "$SUBSCRIBER" --scope public
38
+ ufoo report progress "<detail>" --task <id> --agent "$SUBSCRIBER" --scope public
39
+ ufoo report done "<summary>" --task <id> --agent "$SUBSCRIBER" --scope public
40
+ ufoo report error "<reason>" --task <id> --agent "$SUBSCRIBER" --scope public
34
41
  ```
35
42
 
36
43
  ---
@@ -44,13 +51,21 @@ ufoo ctx decisions -n 1
44
51
  ```
45
52
 
46
53
  Key files in `.ufoo/context/`:
47
- - `DECISIONS/` - Decision log (append-only)
48
- - `SYSTEM.md` - System overview
49
- - `CONSTRAINTS.md` - Non-negotiable rules
54
+ - `decisions/` - Decision log (append-only)
55
+
56
+ **Decision recording policy "If it has information value, write it down":**
57
+
58
+ Record a decision whenever your work produces knowledge that would be useful to your future self, other agents, or the user. The threshold is LOW — when in doubt, record it.
50
59
 
51
- **Decision recording policy:**
52
- - **Must record**: evaluations, architecture, naming, trade-offs
53
- - Write decision **before replying** when applicable
60
+ - **Always record**: architectural choices, trade-off analysis, research findings, non-obvious gotchas, naming/convention changes, external API behavior discovered, performance observations, bug root causes
61
+ - **Also record**: open questions you couldn't resolve, assumptions you made, approaches you considered and rejected (with reasons), edge cases noticed but not handled
62
+ - **Write the decision BEFORE acting on it** if your session dies, the knowledge survives
63
+ - **Granularity**: A decision can be one sentence ("X doesn't support Y, use Z instead") or a multi-page analysis. Match the depth to the information value.
64
+
65
+ ```bash
66
+ ufoo ctx decisions new "Short descriptive title"
67
+ # Then edit the created file with Context/Decision/Implications
68
+ ```
54
69
 
55
70
  ---
56
71
 
@@ -59,9 +74,12 @@ Key files in `.ufoo/context/`:
59
74
  ### CRITICAL: `ubus` Command Behavior
60
75
 
61
76
  **When you receive `ubus`, you MUST:**
62
- 1. Check pending messages: `ufoo bus check $SUBSCRIBER`
63
- 2. **EXECUTE each task immediately** - Do NOT ask the user
64
- 3. Reply to sender: `ufoo bus send "<publisher>" "<result>"`
77
+ 1. Resolve subscriber ID first (reuse existing ID, join only as fallback):
78
+ `SUBSCRIBER="${UFOO_SUBSCRIBER_ID:-$(ufoo bus whoami 2>/dev/null || true)}"; [ -n "$SUBSCRIBER" ] || SUBSCRIBER=$(ufoo bus join | tail -1)`
79
+ 2. Check pending messages: `ufoo bus check $SUBSCRIBER`
80
+ 3. **EXECUTE each task immediately** - Do NOT ask the user
81
+ 4. Reply to sender: `ufoo bus send "<publisher>" "<result>"`
82
+ 5. **CRITICAL: Acknowledge messages after handling**: `ufoo bus ack $SUBSCRIBER`
65
83
 
66
84
  **Rules:**
67
85
  - Execute tasks immediately without asking
@@ -83,5 +101,5 @@ Extract sender ID from "from" field, use it to reply.
83
101
 
84
102
  1. Receive: `@you from claude-code:bd36dda0 Content: {"message":"Please analyze the project structure"}`
85
103
  2. Execute: Analyze the project structure
86
- 3. Reply: `ufoo bus send "claude-code:bd36dda0" "Project contains src/, scripts/, modules/"`
104
+ 3. Reply: `ufoo bus send "claude-code:bd36dda0" "Project contains src/, modules/, bin/"`
87
105
  <!-- /ufoo -->
@@ -22,11 +22,17 @@ ufoo init --modules context,bus
22
22
  ## Directory Structure
23
23
 
24
24
  ```
25
- .bus/
26
- ├── bus.json # Bus metadata + subscriber status
27
- ├── events/ # Event stream (JSONL, sharded by date)
28
- ├── offsets/ # Each Agent's consumption progress
29
- └── queues/ # Targeted event queues
25
+ .ufoo/
26
+ ├── agent/
27
+ │ └── all-agents.json # Agent metadata + agent status
28
+ ├── daemon/
29
+ │ ├── daemon.pid
30
+ │ ├── daemon.log
31
+ │ └── counts/
32
+ └── bus/
33
+ ├── events/ # Event stream (JSONL, sharded by date)
34
+ ├── offsets/ # Each Agent's consumption progress
35
+ └── queues/ # Targeted event queues
30
36
  ```
31
37
 
32
38
  ## Usage
@@ -34,33 +40,34 @@ ufoo init --modules context,bus
34
40
  ### Join Bus
35
41
 
36
42
  ```bash
37
- SUBSCRIBER=$(bash scripts/bus.sh join)
38
- # Output: claude-code:a1b2c3
43
+ SUBSCRIBER="${UFOO_SUBSCRIBER_ID:-$(ufoo bus whoami 2>/dev/null || true)}"
44
+ [ -n "$SUBSCRIBER" ] || SUBSCRIBER=$(ufoo bus join | tail -n 1)
45
+ # Output: claude-code:a1b2c3 (or codex:def456)
39
46
  ```
40
47
 
41
48
  ### Check Pending Messages
42
49
 
43
50
  ```bash
44
- bash scripts/bus.sh check $SUBSCRIBER
51
+ ufoo bus check "$SUBSCRIBER"
45
52
  ```
46
53
 
47
54
  ### Send Messages
48
55
 
49
56
  ```bash
50
57
  # Send to specific instance
51
- bash scripts/bus.sh send "claude-code:abc123" "Please help me review"
58
+ ufoo bus send "claude-code:abc123" "Please help me review"
52
59
 
53
60
  # Send to all instances of same type
54
- bash scripts/bus.sh send "claude-code" "Everyone please review"
61
+ ufoo bus send "claude-code" "Everyone please review"
55
62
 
56
63
  # Broadcast to all
57
- bash scripts/bus.sh broadcast "I completed feature-x"
64
+ ufoo bus broadcast "I completed feature-x"
58
65
  ```
59
66
 
60
67
  ### View Status
61
68
 
62
69
  ```bash
63
- bash scripts/bus.sh status
70
+ ufoo bus status
64
71
  ```
65
72
 
66
73
  ## Notifications/Alerts (no key injection, recommended)
@@ -68,47 +75,48 @@ bash scripts/bus.sh status
68
75
  If you want to receive "new message alerts" while running Codex/Claude in another terminal, use **agent-side alert/listen** (avoids IME/accessibility permission/window positioning fragmentation issues):
69
76
 
70
77
  ```bash
71
- SUBSCRIBER=$(bash scripts/bus.sh join | tail -n 1)
78
+ SUBSCRIBER="${UFOO_SUBSCRIBER_ID:-$(ufoo bus whoami 2>/dev/null || true)}"
79
+ [ -n "$SUBSCRIBER" ] || SUBSCRIBER=$(ufoo bus join | tail -n 1)
72
80
 
73
81
  # Background alert: title badge + bell + optional macOS notification center
74
- bash scripts/bus-alert.sh "$SUBSCRIBER" 1 --notify --daemon
82
+ ufoo bus alert "$SUBSCRIBER" 1 --notify --daemon
75
83
 
76
84
  # Or: foreground continuous print of new messages (suitable for a side terminal)
77
- bash scripts/bus-listen.sh "$SUBSCRIBER" --from-beginning
85
+ ufoo bus listen "$SUBSCRIBER" --from-beginning
78
86
  ```
79
87
 
80
88
  ## Unattended Auto-Execute (recommended)
81
89
 
82
- If you need **Claude A to notify Claude B / Codex C and have the target auto-execute** (e.g., auto-trigger `/ubus`), use `autotrigger`:
90
+ If you need **Claude A to notify Claude B / Codex C and have the target auto-execute** (e.g., auto-trigger `/ubus`), use the bus daemon:
83
91
 
84
- 1) First `join` in each terminal session (records `tty`, also records `TMUX_PANE` if in tmux):
92
+ 1) Resolve subscriber in each terminal session first (records `tty`, also records `TMUX_PANE` if in tmux). Join only as fallback:
85
93
 
86
94
  ```bash
87
- SUBSCRIBER=$(bash scripts/bus.sh join | tail -n 1)
95
+ SUBSCRIBER="${UFOO_SUBSCRIBER_ID:-$(ufoo bus whoami 2>/dev/null || true)}"
96
+ [ -n "$SUBSCRIBER" ] || SUBSCRIBER=$(ufoo bus join | tail -n 1)
88
97
  ```
89
98
 
90
- 2) Start autotrigger in the project (runs as background daemon):
99
+ 2) Start the bus daemon in the project (runs as background daemon):
91
100
 
92
101
  ```bash
93
- # backend=auto prefers tmux (if available), otherwise tries Terminal.app do script (pure Automation), finally Accessibility
94
- bash scripts/bus-autotrigger.sh start --interval 1 --command "/ubus" --backend auto
102
+ ufoo bus daemon --interval 1 --daemon
95
103
  ```
96
104
 
97
- 3) After sending a message, autotrigger injects `/ubus` into the target session and presses Enter:
105
+ 3) After sending a message, the daemon injects `/ubus` into the target session and presses Enter:
98
106
  - tmux: `send-keys`
99
107
  - Terminal.app (pure Automation): `do script` (no Accessibility needed, but requires Automation authorization; compatibility depends on whether target program accepts input)
100
108
  - Terminal.app (Accessibility): System Events (needs Accessibility), injection sequence is Escape + paste + Return (avoids IME issues)
101
109
 
102
110
  Tips:
103
- - Terminal.app backend depends on `tty` in `bus.json`. Execute `join` in the target terminal session (ensure `tty` is not `not a tty`).
111
+ - Terminal.app backend depends on `tty` in `.ufoo/agent/all-agents.json`. Execute `join` in the target terminal session (ensure `tty` is not `not a tty`).
104
112
  - Pure Automation backend needs one-time authorization: System Preferences → Privacy & Security → Automation (allow script to control Terminal).
105
113
  - Accessibility backend needs one-time authorization: System Preferences → Privacy & Security → Accessibility (for Terminal / script host).
106
114
 
107
115
  Stop/view status:
108
116
 
109
117
  ```bash
110
- bash scripts/bus-autotrigger.sh status
111
- bash scripts/bus-autotrigger.sh stop
118
+ ufoo bus daemon --status
119
+ ufoo bus daemon --stop
112
120
  ```
113
121
 
114
122
  ## Subscriber ID Format
@@ -29,18 +29,29 @@ if [[ ! -d ".ufoo/bus" ]]; then
29
29
  fi
30
30
  ```
31
31
 
32
- ### 2. Check if already joined bus
32
+ ### 2. Get or create subscriber ID
33
33
 
34
- Read `.ufoo/bus/bus.json`, check if current session is registered.
35
-
36
- If not, auto-join (will auto-generate a friendly nickname like "codex-1", "claude-1"):
34
+ **IMPORTANT**: Always check for existing subscriber ID first to avoid creating duplicates.
37
35
 
38
36
  ```bash
39
- SUBSCRIBER=$(ufoo bus join | tail -n 1)
40
- echo "Joined event bus: $SUBSCRIBER"
41
- # Example output: codex:0e293156 (nickname: codex-1)
37
+ # Reuse existing subscriber first (env -> whoami), join only if missing
38
+ SUBSCRIBER="${UFOO_SUBSCRIBER_ID:-$(ufoo bus whoami 2>/dev/null || true)}"
39
+ if [ -n "$SUBSCRIBER" ]; then
40
+ echo "Using existing subscriber ID: $SUBSCRIBER"
41
+ else
42
+ # Not launched via uclaude/ucodex, need to join manually
43
+ SUBSCRIBER=$(ufoo bus join | tail -n 1)
44
+ echo "Joined event bus: $SUBSCRIBER"
45
+ # Example output: codex:0e293156 (nickname: codex-1)
46
+ fi
42
47
  ```
43
48
 
49
+ **Why this matters**:
50
+ - `uclaude`/`ucodex` automatically set `UFOO_SUBSCRIBER_ID` during launch
51
+ - `ufoo bus whoami` can recover current ID even when env is missing
52
+ - Re-joining may create identity drift and message routing issues
53
+ - Always reuse existing ID when available
54
+
44
55
  To join with a custom nickname:
45
56
 
46
57
  ```bash
@@ -127,7 +138,7 @@ Output (now includes nicknames):
127
138
  ```
128
139
  === Event Bus Status ===
129
140
  My identity: claude-code:xyz789
130
- Online subscribers: 2
141
+ Online agents: 2
131
142
  - claude-code:abc123 (architect)
132
143
  - claude-code:xyz789 (dev-lead)
133
144
  Recent events: 5
@@ -1,24 +1,12 @@
1
1
  # context
2
2
 
3
- A collaboration protocol that constrains AI behavior through explicit, versioned files.
3
+ Decision-only context module for ufoo.
4
4
 
5
- ## Why
6
-
7
- AI coding agents (Claude Code, Codex, Cursor, etc.) have two fundamental problems:
8
-
9
- 1. **No shared memory** Decisions made in one session are invisible to other agents or future sessions. Each agent starts fresh, repeating mistakes or contradicting prior work.
10
-
11
- This protocol solves it by treating decisions and context as files:
12
- - **Decisions as files** — Persistent, versioned, reviewable. All agents read the same truth.
13
-
14
- ## Core Principle
15
-
16
- ```
17
- Global context defines the law.
18
- Project context defines the truth.
19
- ```
20
-
21
- **Files are truth, not memory.**
5
+ Purpose:
6
+ - Persist decisions in project workspaces
7
+ - Keep decision format canonical in `uctx` skill
8
+
9
+ Bus handles communication; context handles durable decision truth.
22
10
 
23
11
  ## Quick Start
24
12
 
@@ -34,42 +22,32 @@ This repository is the `context` module. The recommended entrypoint is `ufoo`.
34
22
 
35
23
  Global modules live under `~/.ufoo/modules/`.
36
24
 
37
- ### Project: `<project>/.context/` (writable)
25
+ ### Project: `<project>/.ufoo/context/` (writable)
38
26
 
39
27
  ```
40
- .context/
41
- ├── README.md # Entry point / how to use this context
42
- ├── SYSTEM.md # Project architecture
43
- ├── CONSTRAINTS.md # Non-negotiable rules
44
- ├── ASSUMPTIONS.md # Current assumptions
45
- ├── TERMINOLOGY.md # Shared vocabulary
46
- └── DECISIONS/ # Append-only log
28
+ .ufoo/context/
29
+ ├── decisions/ # Append-only decision log (decision-only mode)
30
+ └── decisions.jsonl # Decision index (ts/type/file/author)
47
31
  ```
48
32
 
49
- Must be in Git. Must be reviewable. Truth.
33
+ Should be in the project workspace and writable by agents.
34
+ Versioning is optional but recommended for auditability.
50
35
 
51
- ## Protocol Structure
36
+ ## Module Structure
52
37
 
53
38
  ```
54
39
  context/ # This repo
55
- ├── SYSTEM.md # Protocol definition
56
- ├── RULES.md # Collaboration rules
57
- ├── CONSTRAINTS.md # Protocol constraints
58
- ├── DECISION-PROTOCOL.md # How to write decisions
59
- ├── HANDOFF.md # Session handoff rules
60
- ├── CONTEXT-STRUCTURE.md # Project structure spec
61
- ├── TEMPLATES/ # AI behavior constraint
62
- ├── SKILLS/ # tool skill docs (module-local)
63
- └── .context/ # Local project context for this repo (ignored; not part of protocol distribution)
40
+ ├── README.md # This file
41
+ ├── SKILLS/uctx/SKILL.md # Canonical decision format + workflow
42
+ └── .ufoo/context/ # Local project context for this repo (ignored; not part of protocol distribution)
64
43
  ```
65
44
 
66
45
  ## For AI Agents
67
46
 
68
47
  1. Read installed module from `~/.ufoo/modules/context/`
69
- 2. Read/write context from `<project>/.context/`
48
+ 2. Read/write decisions in `<project>/.ufoo/context/decisions/`
70
49
  3. **Never write to global** — only to project
71
- 4. When unsure, write a decision
72
- 5. Do not modify TEMPLATES/ without a decision
50
+ 4. Follow the decision format in `SKILLS/uctx/SKILL.md`
73
51
 
74
52
  ## Validate
75
53
 
@@ -14,12 +14,74 @@ Fast context check for daily use. Run at session start or anytime.
14
14
 
15
15
  Pre-flight reminder:
16
16
  - If the user is asking for evaluation/recommendation/plan, write a decision before replying.
17
+ Use: `ufoo ctx decisions new "<Title>"`
18
+
19
+ ## Decision format (canonical)
20
+
21
+ Project context is decision-only. Decisions live at:
22
+ `<project>/.ufoo/context/decisions/`
23
+
24
+ Decision index (JSONL):
25
+ `<project>/.ufoo/context/decisions.jsonl`
26
+
27
+ Generate/update the index:
28
+ ```bash
29
+ ufoo ctx decisions index
30
+ ```
31
+
32
+ Each JSONL row includes:
33
+ - `ts` (ISO timestamp)
34
+ - `type` (`decision` or `decision_status`)
35
+ - `file` (decision filename)
36
+ - `author` (decision author or resolver)
37
+
38
+ Create a new decision (recommended before replying when required):
39
+ ```bash
40
+ ufoo ctx decisions new "Short Title"
41
+ ```
42
+
43
+ **File naming:** `NNNN-<nickname>-short-title.md` (4-digit prefix + nickname + kebab-case slug).
44
+
45
+ **Template for new decisions:**
46
+ ```yaml
47
+ ---
48
+ status: open
49
+ nickname: <nickname>
50
+ ---
51
+ # DECISION NNNN: <Title>
52
+
53
+ Date: YYYY-MM-DD
54
+ Author: <agent>
55
+ Nickname: <nickname>
56
+
57
+ Context:
58
+ What led to this decision?
59
+
60
+ Decision:
61
+ What is now considered true?
62
+
63
+ Implications:
64
+ What must follow from this?
65
+ ```
66
+
67
+ **Status updates (only edit frontmatter):**
68
+ ```yaml
69
+ ---
70
+ status: resolved
71
+ resolved_by: <agent>
72
+ resolved_at: YYYY-MM-DD
73
+ ---
74
+ ```
75
+
76
+ Rules:
77
+ - Decisions are append-only. Do not rewrite past content.
78
+ - Only update the frontmatter when changing status.
17
79
 
18
80
  ## Workflow
19
81
 
20
82
  ### 1. Verify structure exists
21
83
 
22
- Check `.ufoo/context/` exists. If missing, tell user to run `uinit` (ufoo init CLI).
84
+ Check `.ufoo/context/decisions/` exists. If missing, tell user to run `ufoo init`.
23
85
 
24
86
  ### 2. List all decisions
25
87