cimux-mcp 0.1.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 (38) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +133 -0
  3. package/dist/cli/cimux-cli.d.ts +10 -0
  4. package/dist/cli/cimux-cli.js +201 -0
  5. package/dist/cli/cimux-cli.js.map +1 -0
  6. package/dist/index.d.ts +15 -0
  7. package/dist/index.js +34 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/install/cimux-install-plan.d.ts +29 -0
  10. package/dist/install/cimux-install-plan.js +187 -0
  11. package/dist/install/cimux-install-plan.js.map +1 -0
  12. package/dist/mcp/cimux-mcp-server.d.ts +4 -0
  13. package/dist/mcp/cimux-mcp-server.js +59 -0
  14. package/dist/mcp/cimux-mcp-server.js.map +1 -0
  15. package/dist/model/context-package.d.ts +913 -0
  16. package/dist/model/context-package.js +153 -0
  17. package/dist/model/context-package.js.map +1 -0
  18. package/dist/registration/mailbox-registration.d.ts +30 -0
  19. package/dist/registration/mailbox-registration.js +48 -0
  20. package/dist/registration/mailbox-registration.js.map +1 -0
  21. package/dist/runtime/mailbox-runtime.d.ts +22 -0
  22. package/dist/runtime/mailbox-runtime.js +50 -0
  23. package/dist/runtime/mailbox-runtime.js.map +1 -0
  24. package/dist/service/cimux-mailbox-service.d.ts +87 -0
  25. package/dist/service/cimux-mailbox-service.js +126 -0
  26. package/dist/service/cimux-mailbox-service.js.map +1 -0
  27. package/dist/storage/mailbox-store.d.ts +22 -0
  28. package/dist/storage/mailbox-store.js +2 -0
  29. package/dist/storage/mailbox-store.js.map +1 -0
  30. package/dist/storage/sqlite-cimux-store.d.ts +21 -0
  31. package/dist/storage/sqlite-cimux-store.js +201 -0
  32. package/dist/storage/sqlite-cimux-store.js.map +1 -0
  33. package/dist/version.d.ts +2 -0
  34. package/dist/version.js +3 -0
  35. package/dist/version.js.map +1 -0
  36. package/docs/mvp-readiness.md +85 -0
  37. package/package.json +51 -0
  38. package/scripts/demo-local-handoff.mjs +73 -0
@@ -0,0 +1,201 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { DatabaseSync } from "node:sqlite";
4
+ import { createContextPackagePreview, contextPackageSchema, mailboxNameSchema, mailboxSchema, normalizeInboxPreviewLimit } from "../model/context-package.js";
5
+ export class SQLiteCimuxStore {
6
+ db;
7
+ constructor(databasePath) {
8
+ // The caller decides where the local Cimux database lives. Production code
9
+ // will point this at ~/.cimux/inbox.sqlite; tests can use a temp path.
10
+ fs.mkdirSync(path.dirname(databasePath), { recursive: true });
11
+ this.db = new DatabaseSync(databasePath);
12
+ this.db.exec("pragma foreign_keys = ON;");
13
+ this.migrate();
14
+ }
15
+ async createMailbox(name) {
16
+ const parsedName = mailboxNameSchema.parse(name);
17
+ const now = new Date().toISOString();
18
+ // Creating a mailbox is idempotent so repeated session registration can
19
+ // safely call this without resetting the durable mailbox record.
20
+ this.db
21
+ .prepare(`insert into mailboxes (name, created_at, last_seen_at)
22
+ values (?, ?, null)
23
+ on conflict(name) do nothing`)
24
+ .run(parsedName, now);
25
+ const mailbox = await this.getMailbox(parsedName);
26
+ if (!mailbox) {
27
+ throw new Error(`Mailbox was not created: ${parsedName}`);
28
+ }
29
+ return mailbox;
30
+ }
31
+ async getMailbox(name) {
32
+ const parsedName = mailboxNameSchema.parse(name);
33
+ const row = this.db
34
+ .prepare("select name, created_at, last_seen_at from mailboxes where name = ?")
35
+ .get(parsedName);
36
+ return row ? toMailbox(row) : null;
37
+ }
38
+ async listMailboxes() {
39
+ const rows = this.db
40
+ .prepare("select name, created_at, last_seen_at from mailboxes order by name asc")
41
+ .all();
42
+ return rows.map(toMailbox);
43
+ }
44
+ async createContextPackage(contextPackage) {
45
+ const parsed = contextPackageSchema.parse(contextPackage);
46
+ await this.assertMailboxExists(parsed.fromMailbox);
47
+ await this.assertMailboxExists(parsed.toMailbox);
48
+ this.db
49
+ .prepare(`insert into context_packages (
50
+ id,
51
+ from_mailbox,
52
+ to_mailbox,
53
+ title,
54
+ summary,
55
+ body,
56
+ tags_json,
57
+ artifacts_json,
58
+ payload_json,
59
+ created_at,
60
+ read_at,
61
+ ack_json
62
+ ) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
63
+ .run(parsed.id, parsed.fromMailbox, parsed.toMailbox, parsed.title, parsed.summary, parsed.body, JSON.stringify(parsed.tags), JSON.stringify(parsed.artifacts), JSON.stringify(parsed.payload), parsed.createdAt, parsed.readAt, JSON.stringify(parsed.ack));
64
+ return parsed;
65
+ }
66
+ async listInboxPreviews(mailboxName, options = {}) {
67
+ const parsedMailboxName = mailboxNameSchema.parse(mailboxName);
68
+ const limit = normalizeInboxPreviewLimit(options.limit);
69
+ const clauses = ["to_mailbox = ?"];
70
+ const params = [parsedMailboxName];
71
+ if (options.unreadOnly) {
72
+ clauses.push("read_at is null");
73
+ }
74
+ params.push(limit);
75
+ const rows = this.db
76
+ .prepare(`select * from context_packages
77
+ where ${clauses.join(" and ")}
78
+ order by created_at desc
79
+ limit ?`)
80
+ .all(...params);
81
+ return rows.map((row) => createContextPackagePreview(toContextPackage(row)));
82
+ }
83
+ async readContextPackage(id) {
84
+ const contextPackage = await this.getContextPackage(id);
85
+ if (!contextPackage) {
86
+ return null;
87
+ }
88
+ if (contextPackage.readAt) {
89
+ return contextPackage;
90
+ }
91
+ const readAt = new Date().toISOString();
92
+ this.db
93
+ .prepare("update context_packages set read_at = ? where id = ?")
94
+ .run(readAt, contextPackage.id);
95
+ return {
96
+ ...contextPackage,
97
+ readAt
98
+ };
99
+ }
100
+ async getContextPackage(id) {
101
+ const row = this.db
102
+ .prepare("select * from context_packages where id = ?")
103
+ .get(id);
104
+ return row ? toContextPackage(row) : null;
105
+ }
106
+ async ackContextPackage(id, options) {
107
+ const contextPackage = await this.getContextPackage(id);
108
+ if (!contextPackage) {
109
+ return null;
110
+ }
111
+ const ackBy = mailboxNameSchema.parse(options.ackBy);
112
+ const ack = {
113
+ status: "acknowledged",
114
+ ackAt: new Date().toISOString(),
115
+ ackBy,
116
+ note: options.note ?? null
117
+ };
118
+ this.db
119
+ .prepare("update context_packages set ack_json = ? where id = ?")
120
+ .run(JSON.stringify(ack), id);
121
+ return {
122
+ ...contextPackage,
123
+ ack
124
+ };
125
+ }
126
+ close() {
127
+ this.db.close();
128
+ }
129
+ async assertMailboxExists(name) {
130
+ const mailbox = await this.getMailbox(name);
131
+ if (!mailbox) {
132
+ throw new UnknownMailboxError(name);
133
+ }
134
+ }
135
+ migrate() {
136
+ // Context Packages reference mailboxes by name. Unknown recipients are
137
+ // rejected at storage time instead of being silently auto-created.
138
+ this.db.exec(`
139
+ create table if not exists mailboxes (
140
+ name text primary key,
141
+ created_at text not null,
142
+ last_seen_at text
143
+ );
144
+
145
+ create table if not exists context_packages (
146
+ id text primary key,
147
+ from_mailbox text not null references mailboxes(name),
148
+ to_mailbox text not null references mailboxes(name),
149
+ title text not null,
150
+ summary text not null,
151
+ body text not null,
152
+ tags_json text not null,
153
+ artifacts_json text not null,
154
+ payload_json text not null,
155
+ created_at text not null,
156
+ read_at text,
157
+ ack_json text not null
158
+ );
159
+
160
+ create index if not exists idx_context_packages_id
161
+ on context_packages (id);
162
+
163
+ create index if not exists idx_context_packages_inbox_created
164
+ on context_packages (to_mailbox, created_at desc);
165
+ `);
166
+ }
167
+ }
168
+ export class UnknownMailboxError extends Error {
169
+ mailboxName;
170
+ constructor(mailboxName) {
171
+ super(`Unknown mailbox: ${mailboxName}`);
172
+ this.mailboxName = mailboxName;
173
+ this.name = "UnknownMailboxError";
174
+ }
175
+ }
176
+ function toMailbox(row) {
177
+ // Validate rows on the way out so database changes cannot silently drift
178
+ // away from the public model contract.
179
+ return mailboxSchema.parse({
180
+ name: row.name,
181
+ createdAt: row.created_at,
182
+ lastSeenAt: row.last_seen_at
183
+ });
184
+ }
185
+ function toContextPackage(row) {
186
+ return contextPackageSchema.parse({
187
+ id: row.id,
188
+ fromMailbox: row.from_mailbox,
189
+ toMailbox: row.to_mailbox,
190
+ title: row.title,
191
+ summary: row.summary,
192
+ body: row.body,
193
+ tags: JSON.parse(row.tags_json),
194
+ artifacts: JSON.parse(row.artifacts_json),
195
+ payload: JSON.parse(row.payload_json),
196
+ createdAt: row.created_at,
197
+ readAt: row.read_at,
198
+ ack: JSON.parse(row.ack_json)
199
+ });
200
+ }
201
+ //# sourceMappingURL=sqlite-cimux-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite-cimux-store.js","sourceRoot":"","sources":["../../src/storage/sqlite-cimux-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EACL,2BAA2B,EAC3B,oBAAoB,EACpB,iBAAiB,EACjB,aAAa,EACb,0BAA0B,EAC3B,MAAM,6BAA6B,CAAC;AAoCrC,MAAM,OAAO,gBAAgB;IACV,EAAE,CAAe;IAElC,YAAY,YAAoB;QAC9B,2EAA2E;QAC3E,uEAAuE;QACvE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9D,IAAI,CAAC,EAAE,GAAG,IAAI,YAAY,CAAC,YAAY,CAAC,CAAC;QACzC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;QAC1C,IAAI,CAAC,OAAO,EAAE,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,IAAY;QAC9B,MAAM,UAAU,GAAG,iBAAiB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACjD,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAErC,wEAAwE;QACxE,iEAAiE;QACjE,IAAI,CAAC,EAAE;aACJ,OAAO,CACN;;sCAE8B,CAC/B;aACA,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;QAExB,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;QAClD,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,4BAA4B,UAAU,EAAE,CAAC,CAAC;QAC5D,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,IAAY;QAC3B,MAAM,UAAU,GAAG,iBAAiB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACjD,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE;aAChB,OAAO,CAAC,qEAAqE,CAAC;aAC9E,GAAG,CAAC,UAAU,CAA2B,CAAC;QAE7C,OAAO,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACrC,CAAC;IAED,KAAK,CAAC,aAAa;QACjB,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE;aACjB,OAAO,CAAC,wEAAwE,CAAC;aACjF,GAAG,EAAkB,CAAC;QAEzB,OAAO,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,oBAAoB,CAAC,cAA8B;QACvD,MAAM,MAAM,GAAG,oBAAoB,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QAE1D,MAAM,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QACnD,MAAM,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAEjD,IAAI,CAAC,EAAE;aACJ,OAAO,CACN;;;;;;;;;;;;;sDAa8C,CAC/C;aACA,GAAG,CACF,MAAM,CAAC,EAAE,EACT,MAAM,CAAC,WAAW,EAClB,MAAM,CAAC,SAAS,EAChB,MAAM,CAAC,KAAK,EACZ,MAAM,CAAC,OAAO,EACd,MAAM,CAAC,IAAI,EACX,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,EAC3B,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC,EAChC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,EAC9B,MAAM,CAAC,SAAS,EAChB,MAAM,CAAC,MAAM,EACb,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAC3B,CAAC;QAEJ,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,KAAK,CAAC,iBAAiB,CACrB,WAAmB,EACnB,UAAoC,EAAE;QAEtC,MAAM,iBAAiB,GAAG,iBAAiB,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QAC/D,MAAM,KAAK,GAAG,0BAA0B,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACxD,MAAM,OAAO,GAAG,CAAC,gBAAgB,CAAC,CAAC;QACnC,MAAM,MAAM,GAA2B,CAAC,iBAAiB,CAAC,CAAC;QAE3D,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;YACvB,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAClC,CAAC;QAED,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAEnB,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE;aACjB,OAAO,CACN;iBACS,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC;;iBAErB,CACV;aACA,GAAG,CAAC,GAAG,MAAM,CAAwB,CAAC;QAEzC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,2BAA2B,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAC/E,CAAC;IAED,KAAK,CAAC,kBAAkB,CAAC,EAAU;QACjC,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC;QACxD,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,cAAc,CAAC,MAAM,EAAE,CAAC;YAC1B,OAAO,cAAc,CAAC;QACxB,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACxC,IAAI,CAAC,EAAE;aACJ,OAAO,CAAC,sDAAsD,CAAC;aAC/D,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,EAAE,CAAC,CAAC;QAElC,OAAO;YACL,GAAG,cAAc;YACjB,MAAM;SACP,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,EAAU;QAChC,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE;aAChB,OAAO,CAAC,6CAA6C,CAAC;aACtD,GAAG,CAAC,EAAE,CAAkC,CAAC;QAE5C,OAAO,GAAG,CAAC,CAAC,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC5C,CAAC;IAED,KAAK,CAAC,iBAAiB,CACrB,EAAU,EACV,OAAiC;QAEjC,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC;QACxD,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,KAAK,GAAG,iBAAiB,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACrD,MAAM,GAAG,GAAa;YACpB,MAAM,EAAE,cAAc;YACtB,KAAK,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YAC/B,KAAK;YACL,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,IAAI;SAC3B,CAAC;QAEF,IAAI,CAAC,EAAE;aACJ,OAAO,CAAC,uDAAuD,CAAC;aAChE,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;QAEhC,OAAO;YACL,GAAG,cAAc;YACjB,GAAG;SACJ,CAAC;IACJ,CAAC;IAED,KAAK;QACH,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;IAClB,CAAC;IAEO,KAAK,CAAC,mBAAmB,CAAC,IAAY;QAC5C,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QAC5C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,mBAAmB,CAAC,IAAI,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IAEO,OAAO;QACb,uEAAuE;QACvE,mEAAmE;QACnE,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;KA2BZ,CAAC,CAAC;IACL,CAAC;CACF;AAED,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IACvB;IAArB,YAAqB,WAAmB;QACtC,KAAK,CAAC,oBAAoB,WAAW,EAAE,CAAC,CAAC;QADtB,gBAAW,GAAX,WAAW,CAAQ;QAEtC,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACpC,CAAC;CACF;AAED,SAAS,SAAS,CAAC,GAAe;IAChC,yEAAyE;IACzE,uCAAuC;IACvC,OAAO,aAAa,CAAC,KAAK,CAAC;QACzB,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,SAAS,EAAE,GAAG,CAAC,UAAU;QACzB,UAAU,EAAE,GAAG,CAAC,YAAY;KAC7B,CAAC,CAAC;AACL,CAAC;AAED,SAAS,gBAAgB,CAAC,GAAsB;IAC9C,OAAO,oBAAoB,CAAC,KAAK,CAAC;QAChC,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,WAAW,EAAE,GAAG,CAAC,YAAY;QAC7B,SAAS,EAAE,GAAG,CAAC,UAAU;QACzB,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAa;QAC3C,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,cAAc,CAAc;QACtD,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,CAA4B;QAChE,SAAS,EAAE,GAAG,CAAC,UAAU;QACzB,MAAM,EAAE,GAAG,CAAC,OAAO;QACnB,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAa;KAC1C,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const name = "cimux";
2
+ export declare const version = "0.1.0";
@@ -0,0 +1,3 @@
1
+ export const name = "cimux";
2
+ export const version = "0.1.0";
3
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,IAAI,GAAG,OAAO,CAAC;AAC5B,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC"}
@@ -0,0 +1,85 @@
1
+ # MVP Readiness
2
+
3
+ This checklist defines the local Cimux MVP: agents can send intentional context to another local agent inbox; receivers can preview, read, and ack; empty inbox checks do not emit prompt context.
4
+
5
+ ## Automated Checks
6
+
7
+ Run before every MVP release candidate:
8
+
9
+ ```bash
10
+ npm test
11
+ npm run typecheck
12
+ npm run build
13
+ npm run demo:local
14
+ npm pack --dry-run
15
+ ```
16
+
17
+ Expected result:
18
+
19
+ - all tests pass
20
+ - the demo sends, notifies, previews, reads, and acks one Context Package
21
+ - the npm tarball includes `dist`, `README.md`, `package.json`, and `scripts/demo-local-handoff.mjs`
22
+
23
+ ## Manual Install Check
24
+
25
+ Run this from the repo on a local machine:
26
+
27
+ ```bash
28
+ npm install
29
+ npm run build
30
+ npm link
31
+ cimux --help
32
+ cimux --version
33
+ cimux install --dry-run
34
+ cimux install
35
+ ```
36
+
37
+ Expected result:
38
+
39
+ - `cimux --help` prints the command list
40
+ - `cimux --version` prints the package version
41
+ - `cimux install --dry-run` prints Codex and Claude config snippets
42
+ - `cimux install` writes config and creates `.cimux.bak` backups before updating existing files
43
+ - a new Codex or Claude session sees the Cimux MCP server after restart
44
+
45
+ ## Harness Verification
46
+
47
+ After installing and restarting the target harness:
48
+
49
+ 1. Confirm the Cimux MCP tools are visible:
50
+ - `register_session`
51
+ - `send_context`
52
+ - `check_inbox`
53
+ - `read_context`
54
+ - `ack_context`
55
+ 2. Start or resume a session in a git repo.
56
+ 3. Confirm the session can register as `harness/branch-name`.
57
+ 4. Send a Context Package to that mailbox.
58
+ 5. Submit a new user prompt to the receiving session.
59
+ 6. Confirm the hook emits one short notification line.
60
+ 7. Confirm `check_inbox` returns previews only.
61
+ 8. Confirm `read_context` returns the full body.
62
+ 9. Confirm `ack_context` marks the package acknowledged.
63
+
64
+ ## Known Limits
65
+
66
+ - Local-only SQLite storage.
67
+ - No hosted auth, workspaces, or SaaS tenancy.
68
+ - No vector database or embeddings.
69
+ - No automatic routing.
70
+ - No remote mailbox sync.
71
+ - No read-only inspector UI yet.
72
+ - Hook notification depends on harness hook support and fires on the next user prompt, not as a real-time interrupt.
73
+ - The installer targets the first supported Codex and Claude config paths and may need more harness-specific hardening before a public release.
74
+
75
+ ## MVP Complete Bar
76
+
77
+ Call the local MVP complete when:
78
+
79
+ - automated checks pass
80
+ - local demo passes
81
+ - manual install check passes on one machine
82
+ - at least one harness can see the MCP tools after install/restart
83
+ - hook notification is verified in that harness
84
+ - README and this checklist match the observed behavior
85
+
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "cimux-mcp",
3
+ "version": "0.1.0",
4
+ "description": "Local-first mailbox for intentional AI agent context handoffs.",
5
+ "keywords": [
6
+ "mcp",
7
+ "agents",
8
+ "context",
9
+ "mailbox",
10
+ "codex",
11
+ "claude"
12
+ ],
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/jackkslash/cimux.git"
16
+ },
17
+ "bugs": {
18
+ "url": "https://github.com/jackkslash/cimux/issues"
19
+ },
20
+ "homepage": "https://github.com/jackkslash/cimux#readme",
21
+ "license": "MIT",
22
+ "type": "module",
23
+ "bin": {
24
+ "cimux": "./dist/index.js"
25
+ },
26
+ "files": [
27
+ "dist",
28
+ "docs",
29
+ "scripts"
30
+ ],
31
+ "scripts": {
32
+ "clean": "node --eval \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
33
+ "build": "npm run clean && tsc -p tsconfig.build.json",
34
+ "demo:local": "npm run build && node scripts/demo-local-handoff.mjs",
35
+ "prepublishOnly": "npm run build && npm test",
36
+ "test": "vitest run",
37
+ "typecheck": "tsc --noEmit"
38
+ },
39
+ "dependencies": {
40
+ "@modelcontextprotocol/sdk": "^1.29.0",
41
+ "zod": "^3.25.76"
42
+ },
43
+ "devDependencies": {
44
+ "@types/node": "^22.13.14",
45
+ "typescript": "^5.8.3",
46
+ "vitest": "^3.2.4"
47
+ },
48
+ "engines": {
49
+ "node": ">=22.13"
50
+ }
51
+ }
@@ -0,0 +1,73 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import fs from "node:fs";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+
6
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "cimux-demo-"));
7
+ const dbPath = path.join(tempDir, "cimux.sqlite");
8
+ const cliPath = path.join(process.cwd(), "dist", "index.js");
9
+
10
+ function run(args) {
11
+ return execFileSync(process.execPath, [cliPath, ...args], {
12
+ cwd: tempDir,
13
+ encoding: "utf8",
14
+ env: {
15
+ ...process.env,
16
+ CIMUX_DB_PATH: dbPath
17
+ }
18
+ }).trim();
19
+ }
20
+
21
+ function runJson(args) {
22
+ return JSON.parse(run(args));
23
+ }
24
+
25
+ console.log("Cimux local handoff demo");
26
+ console.log(`Database: ${dbPath}`);
27
+
28
+ run(["register", "--mailbox", "codex/backend-auth"]);
29
+ run(["register", "--mailbox", "claude/frontend-login"]);
30
+
31
+ const sent = runJson([
32
+ "send",
33
+ "--from",
34
+ "codex/backend-auth",
35
+ "--to",
36
+ "claude/frontend-login",
37
+ "--title",
38
+ "Auth handoff",
39
+ "--summary",
40
+ "Frontend should handle the new auth error.",
41
+ "--body",
42
+ "validateSession now throws ExpiredSessionError.",
43
+ "--tags",
44
+ "auth,frontend"
45
+ ]);
46
+
47
+ console.log(`Sent: ${sent.contextPackage.id}`);
48
+ console.log(run(["notify", "--mailbox", "claude/frontend-login"]));
49
+
50
+ const inbox = runJson(["check", "--mailbox", "claude/frontend-login"]);
51
+ console.log(`Preview count: ${inbox.previews.length}`);
52
+ console.log(`Preview title: ${inbox.previews[0].title}`);
53
+
54
+ const read = runJson([
55
+ "read",
56
+ "--mailbox",
57
+ "claude/frontend-login",
58
+ "--id",
59
+ sent.contextPackage.id
60
+ ]);
61
+ console.log(`Read body: ${read.contextPackage.body}`);
62
+
63
+ const acked = runJson([
64
+ "ack",
65
+ "--mailbox",
66
+ "claude/frontend-login",
67
+ "--id",
68
+ sent.contextPackage.id,
69
+ "--note",
70
+ "Loaded in demo."
71
+ ]);
72
+ console.log(`Ack: ${acked.contextPackage.ack.status}`);
73
+