@hraness/message-like-me 0.8.20 → 0.8.22
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/CHANGELOG.md +42 -18
- package/README.md +49 -37
- package/SECURITY.md +1 -1
- package/dist/cli.js +8 -24
- package/dist/support-runtime.js +197 -29
- package/docs/publishing.md +16 -0
- package/docs/support-foundation-notice.md +2 -2
- package/docs/textbutler/agent-cli.md +4 -4
- package/docs/textbutler/architecture.md +19 -9
- package/docs/textbutler/getting-started.md +99 -27
- package/docs/textbutler/ghostget-contract.md +3 -3
- package/docs/textbutler/javascript-tools.md +63 -0
- package/docs/textbutler/local-data.md +18 -5
- package/docs/textbutler/native-process-plan.md +2 -2
- package/docs/textbutler/native-subscription.md +4 -3
- package/docs/textbutler/readiness.md +3 -3
- package/docs/textbutler/whatsapp.md +1 -1
- package/package.json +7 -5
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
# Start using Textbutler
|
|
2
2
|
|
|
3
|
-
Textbutler is
|
|
4
|
-
inbox and replies you write yourself. Automatic replies stay
|
|
5
|
-
choose a ready agent
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
3
|
+
Textbutler is an AI butler for the iMessage, WhatsApp, and Beeper chats you choose on your Mac.
|
|
4
|
+
Start with its inbox and replies you write yourself. Automatic replies stay
|
|
5
|
+
paused until you choose a ready agent account, turn them on for a contact, and
|
|
6
|
+
resume the butler.
|
|
7
|
+
|
|
8
|
+
AI replies need a local build of Textbutler and a Claude Code, Codex, or Devin
|
|
9
|
+
subscription connected through [xcb](https://github.com/hraness/xcb). The account
|
|
10
|
+
also has to pass `providers check`. Installing doesn't turn replies on, and you
|
|
11
|
+
should test live messaging with a recipient you trust. The Claude API route
|
|
12
|
+
needs a separately reviewed runtime that neither the source checkout nor the
|
|
13
|
+
local build supplies.
|
|
13
14
|
|
|
14
15
|
## Open the guided terminal
|
|
15
16
|
|
|
@@ -27,11 +28,11 @@ bun run textbutler:install
|
|
|
27
28
|
~/.local/bin/textbutler
|
|
28
29
|
```
|
|
29
30
|
|
|
30
|
-
The installer builds a self-contained local
|
|
31
|
-
|
|
32
|
-
its contents and exact Bun runtime before use.
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
The installer builds a self-contained local copy, checks your source files and
|
|
32
|
+
both contact permission profiles against the reviewed record in
|
|
33
|
+
`qualification/`, and verifies its contents and exact Bun runtime before use. If
|
|
34
|
+
the source doesn't match the reviewed record, the build stops. A daemon started
|
|
35
|
+
from source never runs AI replies. The installer starts no services and connects no accounts.
|
|
35
36
|
An existing, different `textbutler` command is preserved. This is a local build,
|
|
36
37
|
not a signed public release. Connect xcb separately for AI replies. Keep the same
|
|
37
38
|
Bun runtime installed. To upgrade a verified existing installation, stop its
|
|
@@ -41,7 +42,7 @@ rollback, and atomically switches the command. It never replaces an unrelated
|
|
|
41
42
|
command or changes your settings. Restart the installed daemon afterward.
|
|
42
43
|
|
|
43
44
|
The terminal has numbered actions for setup, app connections, conversations,
|
|
44
|
-
replies, contacts, pause
|
|
45
|
+
replies, contacts, pause, the menu bar and macOS access. Enter goes back from a selection;
|
|
45
46
|
`q` or Ctrl-C closes the terminal. It does not stop an installed background
|
|
46
47
|
service. Commands below use `bun run textbutler`; the help abbreviates that
|
|
47
48
|
prefix to `textbutler`. You can use `~/.local/bin/textbutler` for these commands.
|
|
@@ -100,9 +101,42 @@ source service is installed.
|
|
|
100
101
|
See [messaging app support](messaging-apps.md) for Beeper limitations and native
|
|
101
102
|
alternatives, including requirements that affect Telegram AI processing.
|
|
102
103
|
|
|
103
|
-
##
|
|
104
|
+
## Shape a contact's butler
|
|
105
|
+
|
|
106
|
+
Contact habitats keep a small owner-authored `soulCore` (voice, relationship
|
|
107
|
+
context, shared context and boundaries) separate from the butler's learned tone
|
|
108
|
+
and formality. The contact-local memory archive can retain 64 sourced notes;
|
|
109
|
+
each reply sees only a small snapshot, and the butler can search older notes
|
|
110
|
+
locally for relevant preferences or open topics. Inspect or clear it with
|
|
111
|
+
`habitats show CONTACT` or `habitats memory-clear CONTACT REVISION`.
|
|
112
|
+
|
|
113
|
+
Search and memory are contact-scoped. JavaScript is separately disabled by
|
|
114
|
+
default; enable it only for a contact whose butler should receive the pure-data
|
|
115
|
+
tool. It runs code in a fresh QuickJS WebAssembly runtime without network,
|
|
116
|
+
filesystem, timers or host APIs, under strict CPU and memory budgets. Exa web
|
|
117
|
+
search remains separately owner-controlled and can send public queries to the
|
|
118
|
+
search provider, so leave it off when that is not wanted.
|
|
119
|
+
|
|
120
|
+
Configure an individual plan while the daemon is paused, using the exact
|
|
121
|
+
revision reported by `habitats show CONTACT`:
|
|
122
|
+
|
|
123
|
+
```sh
|
|
124
|
+
textbutler habitats configure CONTACT REVISION '{"version":1,"guidance":"Be considerate and remember useful shared context without assuming familiarity.","contextMessages":12,"maxReplyCharacters":640,"humor":"match","webSearch":false,"memeSearch":true,"javascript":true,"memorySearch":true,"soulCore":{"voice":"Warm and concise","relationshipContext":"Longtime friend","sharedContext":"They are planning a trip together","boundaries":"Do not make plans or commitments for the owner"}}'
|
|
125
|
+
```
|
|
104
126
|
|
|
105
|
-
|
|
127
|
+
Replace the contact ID and plan values with what you want for that conversation.
|
|
128
|
+
The learned style can evolve from sourced feedback, but it cannot rewrite the
|
|
129
|
+
owner-authored `soulCore` or change tool grants. Tool output is evidence, never
|
|
130
|
+
permission to send a message. See [contact calculation and memory tools](javascript-tools.md)
|
|
131
|
+
for the runtime limits and memory-search behavior.
|
|
132
|
+
|
|
133
|
+
## Give Textbutler access to iMessage
|
|
134
|
+
|
|
135
|
+
In the guided terminal, **Give Textbutler access** walks you through the two
|
|
136
|
+
macOS settings below in order and opens each System Settings pane when you
|
|
137
|
+
press Enter or `o`. It never causes a macOS prompt itself.
|
|
138
|
+
|
|
139
|
+
Use the native app when you want macOS Full Disk Access to belong to `TextButler.app`.
|
|
106
140
|
The app supervises its pinned runtime and background service. Build it from an
|
|
107
141
|
already installed, verified payload on your Mac:
|
|
108
142
|
|
|
@@ -113,15 +147,17 @@ bun run textbutler:app build \
|
|
|
113
147
|
bun run textbutler:app install --from /absolute/new/app-build-directory
|
|
114
148
|
```
|
|
115
149
|
|
|
116
|
-
The default destination is `~/Applications/TextButler.app
|
|
117
|
-
installing the app does not start replies or change
|
|
150
|
+
The default destination is `~/Applications/TextButler.app`, which macOS lists
|
|
151
|
+
as Textbutler. Building and installing the app does not start replies or change
|
|
152
|
+
macOS permissions. macOS never asks for Full Disk Access, so `install` ends
|
|
153
|
+
with a notice; at a terminal, press Enter to open the Full Disk Access pane. In
|
|
118
154
|
**System Settings → Privacy & Security → Full Disk Access**, click **+**, press
|
|
119
155
|
**Command-Shift-G**, enter `~/Applications/TextButler.app`, and choose **Open**.
|
|
120
156
|
Enable its switch. macOS may require your password in its own dialog.
|
|
121
157
|
|
|
122
158
|
Configure the exact Ghostget `src/cli.ts`, Bun runtime, private state directory
|
|
123
159
|
and `imessage:ACCOUNT` binding using `setup` above. This development version pins
|
|
124
|
-
Ghostget 0.18.
|
|
160
|
+
Ghostget 0.18.43 and its reviewed `imsg` helper artifact. Native setup provisions
|
|
125
161
|
that pinned helper into the connector state directory (`imessage transport install`)
|
|
126
162
|
before linking; a missing or mismatched artifact stops setup instead of reaching
|
|
127
163
|
messaging. Setup links only
|
|
@@ -137,6 +173,12 @@ bun run textbutler:app imessage-setup \
|
|
|
137
173
|
--data-dir "$HOME/Library/Application Support/Textbutler"
|
|
138
174
|
```
|
|
139
175
|
|
|
176
|
+
Before macOS asks to let Textbutler control Messages, setup prints a notice;
|
|
177
|
+
press Enter to continue or `s` to skip. If you choose Don't Allow, macOS won't
|
|
178
|
+
ask again: turn on Textbutler in **System Settings → Privacy & Security →
|
|
179
|
+
Automation**, then run the setup command again. `textbutler doctor` shows
|
|
180
|
+
which of these steps is left.
|
|
181
|
+
|
|
140
182
|
After app setup completes, use the installed `daemon install` command to
|
|
141
183
|
register its background service. If an older service is installed, first use
|
|
142
184
|
`daemon uninstall`; this preserves your settings and contacts. Startup verifies
|
|
@@ -153,11 +195,26 @@ with the following command:
|
|
|
153
195
|
bun run textbutler:app install --from /absolute/new/app-build-directory --upgrade
|
|
154
196
|
```
|
|
155
197
|
|
|
198
|
+
Apps now include the Textbutler icon, and releases from before the icon can't
|
|
199
|
+
verify them. To go back to an earlier release, stop the
|
|
200
|
+
service, move `~/Applications/TextButler.app` and `state/macos-app.json` in
|
|
201
|
+
your data folder somewhere safe, then build and install the app from that
|
|
202
|
+
release. Then turn on macOS access for the reinstalled app again.
|
|
203
|
+
|
|
156
204
|
The upgrade verifies both versions and retains the previous signed
|
|
157
205
|
app and receipt. If it reports an uncertain transition, preserve its records
|
|
158
206
|
and reconcile that transition before retrying. Recheck Full Disk Access and
|
|
159
207
|
Messages Automation after the upgrade.
|
|
160
208
|
|
|
209
|
+
Changing the connector's provider implementation changes its reported
|
|
210
|
+
identity. Existing conversation enrollments then report that the provider
|
|
211
|
+
identity changed and must be enrolled again; per-operation owner permissions
|
|
212
|
+
likewise key on the implementation and must be approved again through the
|
|
213
|
+
permission command. Re-enrolling preserves each contact's memory and run
|
|
214
|
+
history: enroll the same conversation coordinate, grant the new binding, and
|
|
215
|
+
update the contact's route reference to the new enrollment in one owner-state
|
|
216
|
+
write, then revoke the superseded grants.
|
|
217
|
+
|
|
161
218
|
See [local data](local-data.md) for retained setup records and installation data
|
|
162
219
|
removal. Repeating setup preserves an already linked account and its identity.
|
|
163
220
|
|
|
@@ -181,8 +238,8 @@ bun run textbutler setup \
|
|
|
181
238
|
--xcb-model FULL_MODEL_KEY
|
|
182
239
|
```
|
|
183
240
|
|
|
184
|
-
For Codex, use `--xcb-account codex:ACCOUNT_ID`
|
|
185
|
-
Repeat setup to add
|
|
241
|
+
For Codex or Devin, use `--xcb-account codex:ACCOUNT_ID` or `--xcb-account devin:ACCOUNT_ID`
|
|
242
|
+
and a matching observed model. Repeat setup to add another provider's account. The command pins the executable bytes and
|
|
186
243
|
explicit routing; it does not activate a contact. Setup refuses changes to an
|
|
187
244
|
existing binary or account/model binding. After an xcb upgrade, stop the daemon
|
|
188
245
|
and review its private `state/host.json` binding before updating the executable
|
|
@@ -244,10 +301,25 @@ bun run textbutler menubar install
|
|
|
244
301
|
`start` opens it now; `install` registers login startup. The first start retrieves
|
|
245
302
|
and verifies the pinned shared native companion. No local Rust build is needed.
|
|
246
303
|
|
|
247
|
-
The menu
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
304
|
+
The menu starts with one status line, then the one thing to do next: start
|
|
305
|
+
Textbutler, open the macOS setting iMessage still needs, read the setup guide,
|
|
306
|
+
or check for replies. **Conversations** holds per-contact replies and agent
|
|
307
|
+
choice, conversation search and app connections; **Pause automatic replies**
|
|
308
|
+
and **Resume automatic replies** sit at the top level. **Details** keeps
|
|
309
|
+
activity, agent accounts and capabilities out of the way. When an action
|
|
310
|
+
doesn't work, a ⚠︎ line under the status says why. Suggestions show a preview
|
|
311
|
+
only: use the terminal to review complete outgoing actions before sending. The
|
|
312
|
+
menu cannot send hidden or truncated draft content.
|
|
313
|
+
|
|
314
|
+
If you installed `TextButler.app`, you can have it run the menu too, so macOS
|
|
315
|
+
lists Textbutler rather than Bun under Login Items. This is off by default while
|
|
316
|
+
the local app identity is checked on a clean macOS account. To try it, use the
|
|
317
|
+
installed command the app was built from:
|
|
318
|
+
`HRANESS_LOCAL_APP=1 ~/.local/bin/textbutler menubar install`. If the app was
|
|
319
|
+
built from another version, the command stops and says so. After
|
|
320
|
+
`bun run textbutler:install --upgrade`, the installer tells you when the menu
|
|
321
|
+
still starts the previous version: run `textbutler menubar install` again, or
|
|
322
|
+
rebuild and upgrade the app when the menu runs through it.
|
|
251
323
|
|
|
252
324
|
Menu startup and daemon startup are separate. Quitting the menu leaves the
|
|
253
325
|
installed daemon running. `menubar stop` closes the menu; `daemon uninstall`
|
|
@@ -8,8 +8,8 @@ menu companion's private helper or open provider databases.
|
|
|
8
8
|
|
|
9
9
|
The automation contract was first admitted with
|
|
10
10
|
[Ghostget 0.18.2](https://github.com/hraness/ghostget/releases/tag/v0.18.2).
|
|
11
|
-
This development version of native TextButler iMessage setup pins Ghostget
|
|
12
|
-
0.18.
|
|
11
|
+
This development version of the native `TextButler.app` iMessage setup pins Ghostget
|
|
12
|
+
0.18.43. Its matching artifact and live conversation checks remain pending.
|
|
13
13
|
The required contract preserves the native helper's resource bundle, avoids
|
|
14
14
|
opening unrelated protected folders during state validation, and exposes bounded
|
|
15
15
|
discovery diagnostics without message bodies. Valid native chat rows without
|
|
@@ -39,7 +39,7 @@ Restarting Textbutler does not silently clear it.
|
|
|
39
39
|
| --- | --- |
|
|
40
40
|
| `status`, `start` | Observe capabilities; explicitly start supported synchronization. |
|
|
41
41
|
| `conversations`, `enroll`, `enrollments` | Exact account generation and direct participant-bound conversation enrollment. |
|
|
42
|
-
| `poll`, `history`, `events` | Bounded history, durable observation cursors, revisions, catch-up and gap detection. |
|
|
42
|
+
| `poll`, `pollSet`, `history`, `events` | Bounded history, durable observation cursors, revisions, catch-up and gap detection; `pollSet` shares one provider session across a contact set and reports each enrollment separately. An enrollment busy with another operation reports its current stored row — not necessarily synced this tick. |
|
|
43
43
|
| `grant`, `grant.get`, `grant.by-intent`, `revoke` | Recipient, action, expiry and quota limits; idempotent issuance lookup and immediate revocation. |
|
|
44
44
|
| `asset`, `prepare` | Admit exact attachment bytes and bind the ordered action list to a context revision and expiry. |
|
|
45
45
|
| `submit`, `cancel`, `run` | Journal an action claim before dispatch and retain accepted, failed, partial or indeterminate results. |
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Contact calculation and memory tools
|
|
2
|
+
|
|
3
|
+
Each contact plan controls two local tools. `memorySearch` defaults to `true` and
|
|
4
|
+
searches that conversation's retained memory archive. `javascript` defaults to
|
|
5
|
+
`false`; enable it in the owner's complete plan with `habitats configure` while
|
|
6
|
+
automatic replies are paused. Learning preserves both flags.
|
|
7
|
+
|
|
8
|
+
Memory search ranks exact words and phrases in the contact's source notes. It
|
|
9
|
+
returns up to eight excerpts with their source IDs, digests, authors and
|
|
10
|
+
categories. Each excerpt contains at most 256 UTF-8 bytes, and the complete result
|
|
11
|
+
fits within 4,096 bytes. Results report omitted matches and shortened text. A
|
|
12
|
+
search reads the archive without changing it or contacting an external service.
|
|
13
|
+
|
|
14
|
+
JavaScript supports small calculations and data transformations. The model supplies
|
|
15
|
+
a synchronous function body and optional JSON input, available as `input`:
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{"kind":"javascript","code":"return input.prices.reduce((total, price) => total + price, 0);","input":{"prices":[12,8,5]}}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The result is JSON, such as `{"ok":true,"value":25}`. A failed calculation returns
|
|
22
|
+
a bounded error code. The model may use the remaining tool call to correct it.
|
|
23
|
+
All tools share the existing limit of two calls per reply.
|
|
24
|
+
|
|
25
|
+
Each calculation runs in a new QuickJS interpreter compiled to WebAssembly. The
|
|
26
|
+
host supplies only copied JSON. There are no file, network, process, module,
|
|
27
|
+
timer or messaging APIs inside the interpreter. `Date` and `Math.random` are
|
|
28
|
+
unavailable. A calculation cannot inspect contact memory unless the reply agent
|
|
29
|
+
passes selected data as input. That data stays on the local host during execution.
|
|
30
|
+
|
|
31
|
+
| Resource | Limit |
|
|
32
|
+
| --- | --- |
|
|
33
|
+
| Code | 8,192 UTF-8 bytes |
|
|
34
|
+
| Input JSON | 16,384 UTF-8 bytes |
|
|
35
|
+
| Output JSON | 4,096 UTF-8 bytes |
|
|
36
|
+
| QuickJS heap | 8 MiB |
|
|
37
|
+
| Interpreter stack | 256 KiB |
|
|
38
|
+
| Cooperative interrupt | 50 ms, with at most 5,000 interrupt checks |
|
|
39
|
+
| Worker watchdog | 250 ms after worker startup; a calculation that misses this gets a resource-limit result and termination is requested |
|
|
40
|
+
| Worker startup | 2,000 ms maximum before a bounded failure result |
|
|
41
|
+
| Worker admission | One active worker, up to sixteen queued calls, with a 5,000 ms queue wait |
|
|
42
|
+
| Input/output structure | 16 levels and 1,024 values |
|
|
43
|
+
|
|
44
|
+
The interpreter checks its deadline during execution and is disposed after every
|
|
45
|
+
call. A separate worker watchdog requests termination if a native engine
|
|
46
|
+
operation fails to reach an interrupt check. The host returns a bounded
|
|
47
|
+
resource-limit result; one worker remains active, and at most sixteen later calls
|
|
48
|
+
wait up to five seconds for its slot. Calls beyond that queue return
|
|
49
|
+
resource-limit. If termination cannot be confirmed, JavaScript stays unavailable
|
|
50
|
+
for that app process and queued calls time out; restarting the app clears the
|
|
51
|
+
fail-closed guard. JSON output rejects pending asynchronous work. Loading the
|
|
52
|
+
interpreter and generating the model response take additional time. The
|
|
53
|
+
WebAssembly runtime and worker have fixed overhead outside the QuickJS heap
|
|
54
|
+
limit.
|
|
55
|
+
|
|
56
|
+
Submitted replies retain tool outcomes for inspection and reflection. JavaScript
|
|
57
|
+
evidence labels the code with its SHA-256 digest. Offline personality evaluation
|
|
58
|
+
does not execute either tool and cannot measure tool behavior from a text replay.
|
|
59
|
+
|
|
60
|
+
The implementation uses the pinned `quickjs-emscripten-core` and embedded
|
|
61
|
+
`@jitl/quickjs-singlefile-browser-release-sync` packages. The upstream
|
|
62
|
+
[runtime documentation](https://github.com/justjake/quickjs-emscripten/blob/main/doc/quickjs-emscripten/classes/QuickJSRuntime.md)
|
|
63
|
+
describes interpreter memory, stack and interrupt controls.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Textbutler keeps settings, contact memory, reply journals and setup records in
|
|
4
4
|
`~/Library/Application Support/Textbutler`, unless you select another data
|
|
5
|
-
directory. These files are private to the Mac user.
|
|
5
|
+
directory. These files are private to the Mac user. xcb and Ghostget keep their
|
|
6
6
|
own accounts and credentials in their separately configured state directories.
|
|
7
7
|
|
|
8
8
|
Explicit CLI media imports live in the selected contact's private `outbox`.
|
|
@@ -24,9 +24,22 @@ directory until completion or rollback is proven. Keep both locations intact
|
|
|
24
24
|
while an upgrade is unresolved.
|
|
25
25
|
|
|
26
26
|
When habitats are enabled, the run journal additionally keeps per-contact
|
|
27
|
-
habitat state (
|
|
28
|
-
follow-up windows, evaluation records
|
|
29
|
-
|
|
27
|
+
habitat state (personality and tool configuration, owner-authored soul anchors,
|
|
28
|
+
learned excerpts, reply episodes, observed follow-up windows, evaluation records
|
|
29
|
+
and rollback history). A reply episode can include up to two tool queries and
|
|
30
|
+
results shortened to 4 KiB each, plus the kinds of actions submitted. Learned
|
|
31
|
+
memory holds up to 64 source-backed 1 KiB excerpts under a 96 KiB encoded archive
|
|
32
|
+
limit, with categories, source message IDs, authors, dates, source digests and
|
|
33
|
+
truncation flags. Digests cover the bounded canonical observations used by
|
|
34
|
+
learning. Episodes retain at most eight 512-byte excerpts shown while composing
|
|
35
|
+
the final reply, plus up to 24 IDs and digests for excerpts exposed only by tool
|
|
36
|
+
steps. Clearing learned memory removes the active excerpts and prevents older
|
|
37
|
+
observations from restoring them; retained episodes, inference records and
|
|
38
|
+
`MEMORY.md` are separate records. JavaScript tool evidence stores a code digest,
|
|
39
|
+
not executable source, and a bounded result.
|
|
40
|
+
Habitat state is limited to 512 KiB per
|
|
41
|
+
contact. The journal keeps the latest 32 replayable inference records per
|
|
42
|
+
contact and a global daily table of API
|
|
30
43
|
usage reservations with their provider-cost settlements. Gateway and other
|
|
31
44
|
provider credentials live under `state/provider-credentials` with owner-only
|
|
32
45
|
permissions; they never enter contact workspaces or journal evidence.
|
|
@@ -47,7 +60,7 @@ needed to settle that operation first.
|
|
|
47
60
|
To erase an installation, the owner can then delete its complete Textbutler
|
|
48
61
|
data directory. This removes settings, contact memory, journals, setup results
|
|
49
62
|
and the iMessage account binding. It does not delete Messages history, Ghostget
|
|
50
|
-
or
|
|
63
|
+
or xcb accounts, or macOS permission grants. Removing individual binding or
|
|
51
64
|
custody records is not a supported way to replace an account or retry a failed
|
|
52
65
|
operation. Reinstalling the command and uninstalling the background service
|
|
53
66
|
both preserve data by default.
|
|
@@ -29,7 +29,7 @@ repository's layout. This change does not activate a provider backend.
|
|
|
29
29
|
application work or turn the operation into success.
|
|
30
30
|
- The existing contact task profile still requires `noCommandTools`, exact tool
|
|
31
31
|
inventory, read/write isolation, isolated configuration, authentication outside
|
|
32
|
-
the workspace and `hostBrokerOnly`.
|
|
32
|
+
the workspace and `hostBrokerOnly`. xcb's persistent coding session is a
|
|
33
33
|
separate explicit profile. It cannot reuse the contact task policy unchanged.
|
|
34
34
|
|
|
35
35
|
## 1. Package-local process seam
|
|
@@ -186,7 +186,7 @@ admission and application factory wiring remain pending:
|
|
|
186
186
|
confinement, relay and account-generation checks retain their existing owners.
|
|
187
187
|
- Keep the current unqualified task paths unavailable until each exact runtime,
|
|
188
188
|
configuration and effective tool inventory has relevant evidence. Add a
|
|
189
|
-
separate persistent coding profile for
|
|
189
|
+
separate persistent coding profile for xcb, with its own application
|
|
190
190
|
authority and lifecycle, rather than widening contact task capabilities.
|
|
191
191
|
|
|
192
192
|
Acceptance requires migration of actual consumers and removal of replaced
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# AI subscriptions through xcb
|
|
2
2
|
|
|
3
3
|
Textbutler uses [xcb (Excalibur)](https://github.com/hraness/xcb) to draft replies
|
|
4
|
-
through an explicitly connected Claude Code or
|
|
4
|
+
through an explicitly connected Claude Code, Codex, or Devin subscription. xcb owns
|
|
5
5
|
provider sign-in, runtime admission, operating-system confinement and account
|
|
6
6
|
custody. Textbutler owns contact context, response policy and every message send.
|
|
7
7
|
Textbutler is an MIT-licensed reference application for this separation.
|
|
@@ -36,8 +36,9 @@ bun run textbutler setup \
|
|
|
36
36
|
--xcb-model FULL_MODEL_KEY
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
Repeat setup with `--xcb-account codex:ACCOUNT_ID`
|
|
40
|
-
|
|
39
|
+
Repeat setup with `--xcb-account codex:ACCOUNT_ID` or `--xcb-account devin:ACCOUNT_ID`
|
|
40
|
+
and the matching full model key to add a Codex or Devin account; one account per
|
|
41
|
+
provider. Setup records the xcb executable's SHA-256 and the explicit
|
|
41
42
|
account/model binding. It does not copy subscription credentials, create a
|
|
42
43
|
provider sign-in or enable a contact. Restart the installed daemon, run `providers list`,
|
|
43
44
|
and use the returned Textbutler account ID with `providers check ACCOUNT_ID`.
|
|
@@ -23,14 +23,14 @@ remain visible in setup and must be resolved before that claim is made.
|
|
|
23
23
|
|
|
24
24
|
## Interface direction
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
xcb is a useful interaction reference: a clear status view, filtered pickers,
|
|
27
27
|
contextual choices, complete review and clean cancellation. Textbutler follows
|
|
28
28
|
that separation with a thin terminal client over its owner control protocol.
|
|
29
29
|
All permission, account, contact, grant and dispatch checks remain in the daemon.
|
|
30
30
|
|
|
31
31
|
The native menu already uses the shared Rust desktop foundation. A new Rust
|
|
32
32
|
runtime is not required to make these controls usable. If the terminal grows
|
|
33
|
-
into a full-screen workspace,
|
|
33
|
+
into a full-screen workspace, xcb's Ratatui/Crossterm interface is an appropriate
|
|
34
34
|
reference. The subscription connection uses xcb's dedicated zero-tool `generate`
|
|
35
35
|
contract. It does not use the workspace coding command or inherit its tools and
|
|
36
36
|
sessions.
|
|
@@ -41,7 +41,7 @@ The verified bundle connects to an explicitly selected xcb installation after
|
|
|
41
41
|
its build checks reviewed composition evidence against current source bytes and
|
|
42
42
|
both contact profiles. A source daemon has no embedded admission and keeps
|
|
43
43
|
subscription inference unavailable. xcb handles
|
|
44
|
-
Claude Code or
|
|
44
|
+
Claude Code, Codex, or Devin subscription authentication, confinement and provider
|
|
45
45
|
custody. Textbutler uses zero-tool generation, parses one operation proposal at
|
|
46
46
|
a time and applies its contact-scoped broker policy before any effect.
|
|
47
47
|
|
|
@@ -8,7 +8,7 @@ credentials, synchronization and send implementation. Textbutler never runs
|
|
|
8
8
|
```mermaid
|
|
9
9
|
flowchart LR
|
|
10
10
|
App[Textbutler menu companion] --> Butler[Textbutler daemon]
|
|
11
|
-
Butler -->
|
|
11
|
+
Butler --> Xcb[xcb]
|
|
12
12
|
Butler --> Ghostget[Ghostget owner process]
|
|
13
13
|
Ghostget --> Messages[iMessage helper]
|
|
14
14
|
Ghostget --> WhatsApp[Pinned wacli linked device]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hraness/message-like-me",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.22",
|
|
4
4
|
"description": "A local-first CLI and Agent Skill for studying private messaging history and drafting messages that sound like you.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -94,15 +94,17 @@
|
|
|
94
94
|
"devDependencies": {
|
|
95
95
|
"@anthropic-ai/claude-agent-sdk": "0.3.268",
|
|
96
96
|
"@anthropic-ai/sdk": "0.125.0",
|
|
97
|
-
"@hraness/agentmixer": "https://github.com/hraness/
|
|
98
|
-
"@hraness/algal": "github:hraness/algal#
|
|
99
|
-
"@hraness/desktop-foundation": "https://github.com/hraness/desktop-foundation/releases/download/v0.
|
|
97
|
+
"@hraness/agentmixer": "https://github.com/hraness/xcb/releases/download/v0.3.0/hraness-agentmixer-0.3.0.tgz",
|
|
98
|
+
"@hraness/algal": "github:hraness/algal#ac68f096d2e10e1824b9ee4d6fe031b4846094da",
|
|
99
|
+
"@hraness/desktop-foundation": "https://github.com/hraness/desktop-foundation/releases/download/v0.8.0/hraness-desktop-foundation-0.8.0.tgz",
|
|
100
100
|
"@hraness/local-custody": "github:hraness/local-custody#v0.4.0",
|
|
101
|
-
"@hraness/support-foundation": "github:hraness/support-foundation#
|
|
101
|
+
"@hraness/support-foundation": "github:hraness/support-foundation#8bb514d24b79dc3f305390700ae312cab88e7ad2",
|
|
102
|
+
"@jitl/quickjs-singlefile-browser-release-sync": "0.32.0",
|
|
102
103
|
"@modelcontextprotocol/sdk": "1.30.0",
|
|
103
104
|
"@types/bun": "1.3.14",
|
|
104
105
|
"effect": "3.22.1",
|
|
105
106
|
"fast-check": "4.9.0",
|
|
107
|
+
"quickjs-emscripten-core": "0.32.0",
|
|
106
108
|
"sigstore": "4.1.1",
|
|
107
109
|
"typescript": "6.0.3",
|
|
108
110
|
"zod": "4.6.2"
|