ticlawk 0.1.12-dev.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +15 -0
- package/README.md +426 -0
- package/agent-freeway.mjs +2 -0
- package/assets/ticlawk-concept.svg +137 -0
- package/bin/agent-freeway.mjs +4 -0
- package/bin/ticlawk.mjs +594 -0
- package/cc-watcher.mjs +3 -0
- package/package.json +72 -0
- package/scripts/postinstall.mjs +61 -0
- package/src/adapters/telegram/index.mjs +359 -0
- package/src/adapters/ticlawk/api.mjs +360 -0
- package/src/adapters/ticlawk/cards.mjs +149 -0
- package/src/adapters/ticlawk/credentials.mjs +25 -0
- package/src/adapters/ticlawk/index.mjs +1229 -0
- package/src/adapters/ticlawk/wake-client.mjs +204 -0
- package/src/core/adapter-registry.mjs +50 -0
- package/src/core/argv.mjs +38 -0
- package/src/core/bindings/store.mjs +81 -0
- package/src/core/bus.mjs +91 -0
- package/src/core/config.mjs +203 -0
- package/src/core/daemon-install.mjs +246 -0
- package/src/core/diagnostics.mjs +79 -0
- package/src/core/events/worker-events.mjs +80 -0
- package/src/core/executables.mjs +106 -0
- package/src/core/host-id.mjs +48 -0
- package/src/core/http.mjs +65 -0
- package/src/core/logger.mjs +34 -0
- package/src/core/media/inbound.mjs +127 -0
- package/src/core/media/outbound.mjs +163 -0
- package/src/core/profiles.mjs +173 -0
- package/src/core/runtime-contract.mjs +68 -0
- package/src/core/runtime-env.mjs +9 -0
- package/src/core/runtime-registry.mjs +93 -0
- package/src/core/runtime-support.mjs +197 -0
- package/src/core/setup-readiness.mjs +86 -0
- package/src/core/store/json-file-store.mjs +47 -0
- package/src/core/ticlawk-control.mjs +92 -0
- package/src/core/uninstall.mjs +142 -0
- package/src/core/update-state.mjs +62 -0
- package/src/core/update.mjs +178 -0
- package/src/runtimes/claude-code/index.mjs +363 -0
- package/src/runtimes/claude-code/session.mjs +388 -0
- package/src/runtimes/claude-code/transcripts.mjs +206 -0
- package/src/runtimes/codex/index.mjs +306 -0
- package/src/runtimes/codex/session.mjs +750 -0
- package/src/runtimes/openclaw/gateway.mjs +269 -0
- package/src/runtimes/openclaw/identity.mjs +34 -0
- package/src/runtimes/openclaw/index.mjs +228 -0
- package/src/runtimes/openclaw/inflight.mjs +46 -0
- package/src/runtimes/openclaw/target.mjs +57 -0
- package/src/runtimes/opencode/index.mjs +318 -0
- package/src/runtimes/opencode/session.mjs +413 -0
- package/src/runtimes/pi/index.mjs +287 -0
- package/src/runtimes/pi/session.mjs +423 -0
- package/ticlawk.mjs +260 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
ISC License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ticlawk
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
10
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
11
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
12
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
13
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
14
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
15
|
+
PERFORMANCE OF THIS SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
# ticlawk
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/ticlawk)
|
|
4
|
+
|
|
5
|
+
**Connect any agent harness to any mobile client.**
|
|
6
|
+
|
|
7
|
+
*M agent harnesses × N mobile clients used to be M×N integrations. ticlawk makes it M+N.*
|
|
8
|
+
|
|
9
|
+
You run the harness locally — Claude Code, Codex, OpenClaw, whatever you're
|
|
10
|
+
testing this week. `ticlawk` is the layer that lets any of them talk
|
|
11
|
+
through any mobile/web client you like to use (Telegram,
|
|
12
|
+
[ticlawk](https://ticlawk.com), more to come).
|
|
13
|
+
|
|
14
|
+
<p align="center">
|
|
15
|
+
<img src="assets/ticlawk-concept.svg" alt="ticlawk connects any client to any agent" width="860">
|
|
16
|
+
</p>
|
|
17
|
+
|
|
18
|
+
Left side: any agent harness that runs on your machine.
|
|
19
|
+
Middle: `ticlawk`.
|
|
20
|
+
Right side: any mobile or web app you like to use to manage your agent.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Quickstart — Telegram in 5 minutes
|
|
25
|
+
|
|
26
|
+
This is the fastest way to see it work. You need a Telegram bot token from
|
|
27
|
+
[@BotFather](https://t.me/BotFather) and a project directory on this machine
|
|
28
|
+
where Claude Code can run.
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# 1. install
|
|
32
|
+
curl -fsSL https://raw.githubusercontent.com/darthjaja6/ticlawk/main/install.sh | bash
|
|
33
|
+
|
|
34
|
+
# 2. choose Telegram as the active adapter
|
|
35
|
+
ticlawk config set adapter telegram
|
|
36
|
+
|
|
37
|
+
# 3. store Telegram auth locally
|
|
38
|
+
ticlawk auth telegram --bot-token <your-bot-token>
|
|
39
|
+
|
|
40
|
+
# 4. restart the daemon so it starts polling the bot
|
|
41
|
+
# Linux
|
|
42
|
+
systemctl --user restart ticlawk
|
|
43
|
+
|
|
44
|
+
# macOS
|
|
45
|
+
launchctl kickstart -k gui/$(id -u)/ticlawk
|
|
46
|
+
|
|
47
|
+
# 5. connect that bot to a Claude Code project
|
|
48
|
+
ticlawk connect --adapter telegram --workdir /path/to/project
|
|
49
|
+
|
|
50
|
+
# optional: if you want to resume an existing Claude Code session instead,
|
|
51
|
+
# add --session-id <claude-session-id>
|
|
52
|
+
|
|
53
|
+
# 6. say hi to your bot on Telegram — the first DM becomes the bot's only chat
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
`--workdir` is the important part. `ticlawk` binds the adapter to a local
|
|
57
|
+
project directory and runtime. `--session-id` is optional: use it only when you
|
|
58
|
+
want to resume an existing Claude Code or Codex conversation instead of letting
|
|
59
|
+
the next message create a fresh session automatically.
|
|
60
|
+
|
|
61
|
+
**Finding `<claude-session-id>`** — if you want to resume, use the filename
|
|
62
|
+
(without `.jsonl`) of the transcript under `~/.claude/projects/**/`. Pick the
|
|
63
|
+
one whose working directory matches the project you want the bot to work on.
|
|
64
|
+
|
|
65
|
+
If `hello` in Telegram comes back as a reply from that Claude Code session,
|
|
66
|
+
you're done. Everything below is for when you want ticlawk, Codex, OpenClaw,
|
|
67
|
+
or more control.
|
|
68
|
+
|
|
69
|
+
> ⚠️ **Single user, by design.** The Telegram bot binds to the **first** private
|
|
70
|
+
> DM that messages it, and refuses everyone else. This is not a bug — it's the
|
|
71
|
+
> security boundary. The bot can run shell commands and edit files in your
|
|
72
|
+
> project; locking it to one chat keeps that capability where you intended.
|
|
73
|
+
> Don't add the bot to groups, and don't share its token.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Using ticlawk instead of Telegram
|
|
78
|
+
|
|
79
|
+
If you want the [ticlawk mobile app](https://ticlawk.com) instead, connect from
|
|
80
|
+
the project directory and scan the QR code with ticlawk. `ticlawk` will
|
|
81
|
+
detect local runtimes in that directory, and ticlawk will ask you which one to
|
|
82
|
+
connect:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
cd /path/to/project
|
|
86
|
+
ticlawk connect
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Full walkthrough: [docs/clients/ticlawk.md](docs/clients/ticlawk.md).
|
|
90
|
+
Telegram details: [docs/clients/telegram.md](docs/clients/telegram.md).
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Using Codex, OpenClaw, or opencode instead of Claude Code
|
|
95
|
+
|
|
96
|
+
Keep the same two-step adapter flow:
|
|
97
|
+
|
|
98
|
+
1. `ticlawk auth <adapter> ...`
|
|
99
|
+
2. `ticlawk connect --adapter <adapter> ...`
|
|
100
|
+
|
|
101
|
+
Then swap the runtime locator with `--type`:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
# Telegram + Codex
|
|
105
|
+
ticlawk connect --adapter telegram --type codex --workdir /path/to/project
|
|
106
|
+
|
|
107
|
+
# ticlawk + Codex, when you want to bypass mobile runtime selection
|
|
108
|
+
ticlawk connect --adapter ticlawk --type codex --workdir /path/to/project
|
|
109
|
+
|
|
110
|
+
# Telegram + OpenClaw
|
|
111
|
+
ticlawk connect --adapter telegram --type openclaw --agent-id main
|
|
112
|
+
|
|
113
|
+
# ticlawk + OpenClaw
|
|
114
|
+
ticlawk connect --adapter ticlawk --type openclaw --agent-id main
|
|
115
|
+
|
|
116
|
+
# Telegram + opencode
|
|
117
|
+
ticlawk connect --adapter telegram --type opencode --workdir /path/to/project
|
|
118
|
+
|
|
119
|
+
# ticlawk + opencode, when you want to bypass mobile runtime selection
|
|
120
|
+
ticlawk connect --adapter ticlawk --type opencode --workdir /path/to/project
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Runtime locators at a glance:
|
|
124
|
+
|
|
125
|
+
| Runtime | Required | Optional resume handle | Where to find it |
|
|
126
|
+
|-------------|----------------|------------------------|---------------------------------------------------------------|
|
|
127
|
+
| Claude Code | `--workdir` | `--session-id` | filename of `~/.claude/projects/**/*.jsonl` (without `.jsonl`)|
|
|
128
|
+
| Codex | `--workdir` | `--session-id` | `payload.id` in the first `session_meta` record of `~/.codex/sessions/**/*.jsonl` |
|
|
129
|
+
| OpenClaw | `--agent-id` | none | logical agent name (`main` by default) |
|
|
130
|
+
| opencode | `--workdir` | `--session-id` (with `--workdir`) | `.id` from `opencode session list --format json` (run inside the project dir) |
|
|
131
|
+
|
|
132
|
+
[OpenClaw](https://github.com/openclaw/openclaw) is an open-source local-first
|
|
133
|
+
agent runtime; skip this row if you don't use it.
|
|
134
|
+
|
|
135
|
+
OpenClaw has built-in channels; use `ticlawk` only if you want a single
|
|
136
|
+
chat surface across Claude Code, Codex, OpenClaw, and opencode.
|
|
137
|
+
|
|
138
|
+
[opencode](https://opencode.ai) is provider-agnostic — it doesn't carry its own
|
|
139
|
+
account system. Before connecting through `ticlawk`, install the CLI
|
|
140
|
+
(`npm i -g opencode-ai`) and authenticate it once against the LLM provider
|
|
141
|
+
you want it to use (`opencode auth login`, then pick Anthropic / OpenAI /
|
|
142
|
+
Google / OpenRouter / etc. and paste the corresponding API key). Model
|
|
143
|
+
selection lives in opencode's own config (`opencode.json` in the project
|
|
144
|
+
root, or user-level config) — `ticlawk` does not pass `--model`.
|
|
145
|
+
|
|
146
|
+
`ticlawk` spawns opencode with `--dangerously-skip-permissions`
|
|
147
|
+
(matching how Codex is wired), so chat messages can drive shell commands and
|
|
148
|
+
file edits in the bound `--workdir` without further confirmation prompts.
|
|
149
|
+
This is the same security boundary documented above; only connect a workdir
|
|
150
|
+
you trust to a chat you control.
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## `auth` vs `connect`
|
|
155
|
+
|
|
156
|
+
You only need to know this once:
|
|
157
|
+
|
|
158
|
+
- **`auth`** — store adapter-specific setup input locally.
|
|
159
|
+
Telegram takes `--bot-token`. ticlawk uses QR pairing from `connect`.
|
|
160
|
+
- **`connect`** — connect the selected adapter to a local runtime.
|
|
161
|
+
For ticlawk, `ticlawk connect` auto-detects local runtimes and
|
|
162
|
+
lets you pick in the mobile app. Use `--workdir` for Telegram or explicit
|
|
163
|
+
ticlawk runtime selection, optionally add `--session-id` to resume, or use
|
|
164
|
+
`--agent-id` for OpenClaw.
|
|
165
|
+
|
|
166
|
+
`auth` is adapter-specific by subcommand shape:
|
|
167
|
+
- `ticlawk auth telegram --bot-token ...`
|
|
168
|
+
|
|
169
|
+
That keeps adapter auth flags scoped to the adapter without making users learn
|
|
170
|
+
the `--` passthrough convention.
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## Daily use
|
|
175
|
+
|
|
176
|
+
After setup, the usual workflow is simple:
|
|
177
|
+
|
|
178
|
+
- Keep `ticlawk` running as a user service. If Linux prints an
|
|
179
|
+
`Action required` message during install or connect, run the command it
|
|
180
|
+
shows so the daemon keeps running after logout and reboot.
|
|
181
|
+
- Keep using the same Telegram chat or ticlawk channel. The adapter auth and
|
|
182
|
+
channel binding stay on disk until you change them.
|
|
183
|
+
- If you want to have the work done just like tiktoking, run
|
|
184
|
+
`ticlawk connect ...` again with the new `--workdir`.
|
|
185
|
+
- If you want to resume an existing Claude Code or Codex conversation, add
|
|
186
|
+
`--session-id`; otherwise the next message creates a fresh session.
|
|
187
|
+
- If an OpenClaw agent changes, reconnect with the new `--agent-id`.
|
|
188
|
+
- If replies stop because the local runtime session ended, run `connect` again
|
|
189
|
+
or reset the session from the client UI.
|
|
190
|
+
- `ticlawk health` is the first thing to check when something feels off.
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## Verifying and troubleshooting
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
ticlawk health
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
- `ok: true` and the adapter-specific fields populated → you're good.
|
|
201
|
+
- Can't reach `127.0.0.1:8741` → the daemon isn't running. Start it with
|
|
202
|
+
`systemctl --user restart ticlawk`,
|
|
203
|
+
`launchctl kickstart -k gui/$(id -u)/ticlawk`, or `ticlawk start`.
|
|
204
|
+
- Telegram shows `runtimeConnected: true` and `connectedChat: false` →
|
|
205
|
+
send the first DM to the bot to claim its only chat.
|
|
206
|
+
- Telegram shows `botConfigured: false` → rerun
|
|
207
|
+
`ticlawk auth telegram --bot-token ...`, then restart the daemon.
|
|
208
|
+
- ticlawk shows `apiKey: false` → rerun `ticlawk connect`
|
|
209
|
+
from the project directory and scan the QR code.
|
|
210
|
+
|
|
211
|
+
Logs:
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
tail -f ~/.ticlawk/ticlawk.log # normal output
|
|
215
|
+
tail -f ~/.ticlawk/ticlawk-crash.log # crashes, signals, exit diagnostics
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## What the installer does
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
curl -fsSL https://raw.githubusercontent.com/darthjaja6/ticlawk/main/install.sh | bash
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
It expects local `node` and `npm`, then:
|
|
227
|
+
|
|
228
|
+
- installs or updates the npm package with `npm install -g ticlawk`
|
|
229
|
+
- creates `~/.ticlawk/` for config and logs
|
|
230
|
+
- installs a user-level service — systemd on Linux, launchd on macOS — so the
|
|
231
|
+
daemon restarts automatically
|
|
232
|
+
|
|
233
|
+
On Linux, if systemd linger is off, the installer prints:
|
|
234
|
+
|
|
235
|
+
```text
|
|
236
|
+
Action required
|
|
237
|
+
|
|
238
|
+
ticlawk may stop when you log out because systemd linger is off.
|
|
239
|
+
|
|
240
|
+
Run this command to keep it running after logout and reboot:
|
|
241
|
+
sudo loginctl enable-linger <user>
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
Prefer not to `curl | bash`? Install with npm, then connect from the project
|
|
245
|
+
directory you want the agent to use:
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
npm install -g ticlawk
|
|
249
|
+
ticlawk connect
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
`connect` saves the pairing and refreshes the background service. If Linux
|
|
253
|
+
systemd linger is off, it prints the same `Action required` message shown by
|
|
254
|
+
the installer.
|
|
255
|
+
|
|
256
|
+
Update with `ticlawk update`. To remove the service and legacy managed
|
|
257
|
+
install files while keeping `~/.ticlawk` config, bindings, profiles, and
|
|
258
|
+
logs:
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
ticlawk uninstall
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
That removes:
|
|
265
|
+
|
|
266
|
+
- legacy `~/.local/share/ticlawk`
|
|
267
|
+
- legacy `~/.local/bin/ticlawk`
|
|
268
|
+
- `~/.config/systemd/user/ticlawk.service` (Linux)
|
|
269
|
+
- `~/Library/LaunchAgents/ticlawk.plist` (macOS)
|
|
270
|
+
|
|
271
|
+
`~/.ticlawk` is preserved. Use `npm uninstall -g ticlawk` to remove
|
|
272
|
+
the npm package itself.
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## Config
|
|
277
|
+
|
|
278
|
+
Config lives in `~/.ticlawk/.config`. Most people only need to set
|
|
279
|
+
`adapter`, then use `auth` for adapter-specific setup. The dotted
|
|
280
|
+
credential keys below still exist for manual or advanced setups.
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
ticlawk config # show current config
|
|
284
|
+
ticlawk config set adapter telegram # or: ticlawk
|
|
285
|
+
ticlawk auth telegram --bot-token <t>
|
|
286
|
+
ticlawk config set telegram.bot-token <t> # advanced/manual override
|
|
287
|
+
ticlawk config set ticlawk.connector-api-key <k> # advanced/manual override
|
|
288
|
+
ticlawk config set ticlawk.connector-ws-url <url> # advanced/manual override
|
|
289
|
+
ticlawk config set streaming off # disable streaming output globally
|
|
290
|
+
ticlawk config set streaming.codex on # force streaming on for codex only
|
|
291
|
+
ticlawk config set streaming.codex default # clear the codex override; inherit the global setting
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
Key mapping (for anyone editing the file directly):
|
|
295
|
+
|
|
296
|
+
| Config key | Env var |
|
|
297
|
+
|-----------------------|----------------------|
|
|
298
|
+
| `adapter` | `AF_ADAPTER` |
|
|
299
|
+
| `telegram.bot-token` | `TELEGRAM_BOT_TOKEN` |
|
|
300
|
+
| `ticlawk.connector-api-key` | `TICLAWK_CONNECTOR_API_KEY` |
|
|
301
|
+
| `ticlawk.api-url` | `TICLAWK_API_URL` |
|
|
302
|
+
| `ticlawk.connector-ws-url` | `TICLAWK_CONNECTOR_WS_URL` |
|
|
303
|
+
|
|
304
|
+
Streaming defaults to on. Full CLI reference: `ticlawk help`.
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
## CLI reference
|
|
309
|
+
|
|
310
|
+
<!-- usage:start -->
|
|
311
|
+
```text
|
|
312
|
+
ticlawk
|
|
313
|
+
|
|
314
|
+
Usage:
|
|
315
|
+
ticlawk help
|
|
316
|
+
ticlawk help <command>
|
|
317
|
+
ticlawk start
|
|
318
|
+
ticlawk health
|
|
319
|
+
ticlawk config
|
|
320
|
+
ticlawk config get <adapter|streaming...|runtimes.claude_code.path|runtimes.codex.path|runtimes.opencode.path|runtimes.pi.path|telegram.bot-token|ticlawk.connector-api-key|ticlawk.api-url|ticlawk.connector-ws-url>
|
|
321
|
+
ticlawk config set <adapter|streaming...|runtimes.claude_code.path|runtimes.codex.path|runtimes.opencode.path|runtimes.pi.path|telegram.bot-token|ticlawk.connector-api-key|ticlawk.api-url|ticlawk.connector-ws-url> <value>
|
|
322
|
+
ticlawk auth <adapter> [adapter-auth-args...]
|
|
323
|
+
ticlawk connect [ticlawk] [codex|claude|opencode|openclaw|pi] [runtime args...]
|
|
324
|
+
ticlawk connect [--adapter <adapter>] [--session-id <id>] --workdir <dir> [--switch-user]
|
|
325
|
+
ticlawk connect [--adapter <adapter>] --type codex [--session-id <id>] --workdir <dir> [--name <name>] [--runtime-path <path>] [--switch-user]
|
|
326
|
+
ticlawk connect [--adapter <adapter>] --type openclaw --agent-id <id> [--name <name>] [--runtime-path <path>] [--switch-user]
|
|
327
|
+
ticlawk connect [--adapter <adapter>] --type opencode [--session-id <id>] --workdir <dir> [--name <name>] [--runtime-path <path>] [--switch-user]
|
|
328
|
+
ticlawk connect [--adapter <adapter>] --type pi [--session-id <id>] --workdir <dir> [--name <name>] [--runtime-path <path>] [--switch-user]
|
|
329
|
+
ticlawk profile list
|
|
330
|
+
ticlawk profile current
|
|
331
|
+
ticlawk profile use ticlawk:<user-id>
|
|
332
|
+
ticlawk install-daemon
|
|
333
|
+
ticlawk update [-y]
|
|
334
|
+
ticlawk uninstall [-y]
|
|
335
|
+
ticlawk version
|
|
336
|
+
|
|
337
|
+
Commands:
|
|
338
|
+
auth store adapter-specific auth/setup input locally
|
|
339
|
+
connect connect the selected adapter to a local runtime
|
|
340
|
+
profile list or switch saved local identities
|
|
341
|
+
install-daemon install or refresh the background daemon
|
|
342
|
+
update update the npm package and refresh the daemon
|
|
343
|
+
uninstall remove service and legacy install files, preserving ~/.ticlawk
|
|
344
|
+
|
|
345
|
+
Config examples:
|
|
346
|
+
ticlawk config get adapter
|
|
347
|
+
ticlawk config set adapter telegram
|
|
348
|
+
ticlawk config set adapter ticlawk
|
|
349
|
+
ticlawk config set streaming off # turn streaming off for all runtimes
|
|
350
|
+
ticlawk config set streaming.codex default # clear the codex-specific override and inherit the global streaming setting
|
|
351
|
+
ticlawk config set runtimes.claude_code.path /path/to/claude_code # advanced/manual
|
|
352
|
+
ticlawk config set runtimes.codex.path /path/to/codex # advanced/manual
|
|
353
|
+
ticlawk config set runtimes.opencode.path /path/to/opencode # advanced/manual
|
|
354
|
+
ticlawk config set runtimes.pi.path /path/to/pi # advanced/manual
|
|
355
|
+
ticlawk config set telegram.bot-token <bot-token> # advanced/manual
|
|
356
|
+
ticlawk config set ticlawk.connector-api-key <key> # advanced/manual
|
|
357
|
+
ticlawk config set ticlawk.api-url <api-url> # advanced/manual
|
|
358
|
+
ticlawk config set ticlawk.connector-ws-url <url> # advanced/manual
|
|
359
|
+
|
|
360
|
+
Examples:
|
|
361
|
+
ticlawk connect
|
|
362
|
+
ticlawk connect ticlawk
|
|
363
|
+
ticlawk connect ticlawk codex
|
|
364
|
+
ticlawk connect ticlawk openclaw --agent-id main
|
|
365
|
+
ticlawk auth telegram --bot-token <bot-token>
|
|
366
|
+
ticlawk connect --adapter telegram --workdir /path/to/project
|
|
367
|
+
ticlawk connect --adapter telegram --session-id <claude-session-id>
|
|
368
|
+
ticlawk connect --adapter telegram --type codex --workdir /path/to/project
|
|
369
|
+
ticlawk connect --adapter telegram --type openclaw --agent-id main
|
|
370
|
+
ticlawk connect --adapter telegram --type opencode --workdir /path/to/project
|
|
371
|
+
ticlawk connect --adapter telegram --type pi --workdir /path/to/project
|
|
372
|
+
```
|
|
373
|
+
<!-- usage:end -->
|
|
374
|
+
|
|
375
|
+
---
|
|
376
|
+
|
|
377
|
+
## Security model
|
|
378
|
+
|
|
379
|
+
This is the part to read before you set anything up.
|
|
380
|
+
|
|
381
|
+
- **The bot can run code on your machine.** Whatever Claude Code / Codex /
|
|
382
|
+
OpenClaw can do in the bound `--workdir`, the chat client can ask it to do.
|
|
383
|
+
Treat the chat as you'd treat a shell.
|
|
384
|
+
- **Single chat, single user.** The Telegram adapter binds to the first private
|
|
385
|
+
DM and rejects all others. The ticlawk adapter binds to one channel per
|
|
386
|
+
connect. Don't share bot tokens or connector credentials.
|
|
387
|
+
- **Secrets stay local.** Bot tokens, ticlawk API keys, and binding metadata
|
|
388
|
+
live in `~/.ticlawk/.config` (mode `0600`) and never leave your
|
|
389
|
+
machine. The daemon listens on `127.0.0.1:8741` only — it does not bind to
|
|
390
|
+
any external interface.
|
|
391
|
+
- **Token leak = remote shell.** If your Telegram bot token leaks, anyone with
|
|
392
|
+
it can take over the bot and start a chat as the first DM. Rotate via
|
|
393
|
+
[@BotFather](https://t.me/BotFather) immediately. Same applies to a leaked
|
|
394
|
+
ticlawk connector API key — revoke it from the ticlawk app.
|
|
395
|
+
- **No telemetry.** `ticlawk` does not send analytics or usage data
|
|
396
|
+
anywhere. The only outbound traffic is to Telegram (when the telegram
|
|
397
|
+
adapter is active) or to your configured ticlawk API URL (default
|
|
398
|
+
`ticlawk.com`, when the ticlawk adapter is active).
|
|
399
|
+
|
|
400
|
+
---
|
|
401
|
+
|
|
402
|
+
## How it works
|
|
403
|
+
|
|
404
|
+
1. You send a message in Telegram or ticlawk.
|
|
405
|
+
2. The adapter delivers it to the local `ticlawk` daemon.
|
|
406
|
+
3. The daemon routes it into the bound Claude Code / Codex / OpenClaw session
|
|
407
|
+
on your machine.
|
|
408
|
+
4. The runtime replies; `ticlawk` captures the output (including
|
|
409
|
+
streaming tokens and supported artifacts).
|
|
410
|
+
5. The reply goes back through the adapter to the same chat.
|
|
411
|
+
|
|
412
|
+
For ticlawk inbound delivery, `ticlawk` keeps a WebSocket connection to
|
|
413
|
+
the ticlawk connector wake endpoint. Wake events such as `jobs.available` and
|
|
414
|
+
`bindings.changed` do not include message text, media, or task payloads. On wake,
|
|
415
|
+
the local daemon uses the existing HTTP APIs to claim pending jobs and refresh
|
|
416
|
+
channel bindings. The durable queue and `claim-pending` API remain the only
|
|
417
|
+
ownership boundary. By default the wake endpoint is
|
|
418
|
+
`wss://edge.ticlawk.com/functions/v1/connector-wake`; override it with
|
|
419
|
+
`ticlawk.connector-ws-url` only for local development or advanced setups.
|
|
420
|
+
Low-frequency recovery audits still run so a missed wake or reconnect window
|
|
421
|
+
does not strand durable jobs; they stay slow and do not speed up when the wake
|
|
422
|
+
connection is disconnected.
|
|
423
|
+
|
|
424
|
+
The daemon owns the binding — which adapter target talks to which local
|
|
425
|
+
runtime, and the metadata needed to resume that runtime later. Adapters own
|
|
426
|
+
their own authentication. That's the whole architecture.
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
<svg width="960" height="520" viewBox="0 0 960 520" fill="none" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="title desc">
|
|
2
|
+
<title id="title">ticlawk connects any client to any agent</title>
|
|
3
|
+
<desc id="desc">A hub-and-spoke diagram with clients on the left, ticlawk in the center, and agent runtimes on the right.</desc>
|
|
4
|
+
|
|
5
|
+
<defs>
|
|
6
|
+
<linearGradient id="hub" x1="372" y1="162" x2="588" y2="378" gradientUnits="userSpaceOnUse">
|
|
7
|
+
<stop stop-color="#1D4ED8"/>
|
|
8
|
+
<stop offset="0.52" stop-color="#0F766E"/>
|
|
9
|
+
<stop offset="1" stop-color="#7C2D12"/>
|
|
10
|
+
</linearGradient>
|
|
11
|
+
<linearGradient id="clientLine" x1="180" y1="72" x2="460" y2="260" gradientUnits="userSpaceOnUse">
|
|
12
|
+
<stop stop-color="#2563EB"/>
|
|
13
|
+
<stop offset="1" stop-color="#0F766E"/>
|
|
14
|
+
</linearGradient>
|
|
15
|
+
<linearGradient id="agentLine" x1="500" y1="260" x2="780" y2="448" gradientUnits="userSpaceOnUse">
|
|
16
|
+
<stop stop-color="#0F766E"/>
|
|
17
|
+
<stop offset="1" stop-color="#C2410C"/>
|
|
18
|
+
</linearGradient>
|
|
19
|
+
<filter id="shadow" x="-20%" y="-20%" width="140%" height="140%" color-interpolation-filters="sRGB">
|
|
20
|
+
<feDropShadow dx="0" dy="10" stdDeviation="16" flood-color="#0F172A" flood-opacity="0.12"/>
|
|
21
|
+
</filter>
|
|
22
|
+
<style>
|
|
23
|
+
.label { fill: #0f172a; font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; font-weight: 700; font-size: 16px; }
|
|
24
|
+
.small { fill: #475569; font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; font-weight: 600; font-size: 13px; }
|
|
25
|
+
.hubText { fill: white; font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; font-weight: 800; font-size: 27px; }
|
|
26
|
+
.hubSub { fill: #E0F2FE; font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; font-weight: 650; font-size: 13px; letter-spacing: 0.08em; }
|
|
27
|
+
.caption { fill: #334155; font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; font-weight: 650; font-size: 14px; }
|
|
28
|
+
.node { fill: #FFFFFF; stroke: #CBD5E1; stroke-width: 1.4; }
|
|
29
|
+
.dot { fill: #F8FAFC; stroke: #CBD5E1; stroke-width: 1.4; }
|
|
30
|
+
</style>
|
|
31
|
+
</defs>
|
|
32
|
+
|
|
33
|
+
<rect width="960" height="520" rx="22" fill="#F8FAFC"/>
|
|
34
|
+
<rect x="24" y="24" width="912" height="472" rx="18" fill="#FFFFFF" stroke="#E2E8F0"/>
|
|
35
|
+
|
|
36
|
+
<text x="180" y="64" text-anchor="middle" class="caption">Any client surface</text>
|
|
37
|
+
<text x="780" y="64" text-anchor="middle" class="caption">Any agent runtime</text>
|
|
38
|
+
|
|
39
|
+
<path d="M230 116 C310 126 350 166 405 215" stroke="url(#clientLine)" stroke-width="4" stroke-linecap="round"/>
|
|
40
|
+
<path d="M230 188 C310 192 354 216 405 244" stroke="url(#clientLine)" stroke-width="4" stroke-linecap="round"/>
|
|
41
|
+
<path d="M230 260 C306 260 348 260 405 260" stroke="url(#clientLine)" stroke-width="4" stroke-linecap="round"/>
|
|
42
|
+
<path d="M230 332 C310 328 354 304 405 276" stroke="url(#clientLine)" stroke-width="4" stroke-linecap="round"/>
|
|
43
|
+
<path d="M230 404 C310 394 350 354 405 305" stroke="url(#clientLine)" stroke-width="4" stroke-linecap="round"/>
|
|
44
|
+
|
|
45
|
+
<path d="M555 215 C610 166 650 126 730 116" stroke="url(#agentLine)" stroke-width="4" stroke-linecap="round"/>
|
|
46
|
+
<path d="M555 244 C606 216 650 192 730 188" stroke="url(#agentLine)" stroke-width="4" stroke-linecap="round"/>
|
|
47
|
+
<path d="M555 260 C612 260 654 260 730 260" stroke="url(#agentLine)" stroke-width="4" stroke-linecap="round"/>
|
|
48
|
+
<path d="M555 276 C606 304 650 328 730 332" stroke="url(#agentLine)" stroke-width="4" stroke-linecap="round"/>
|
|
49
|
+
<path d="M555 305 C610 354 650 394 730 404" stroke="url(#agentLine)" stroke-width="4" stroke-linecap="round"/>
|
|
50
|
+
|
|
51
|
+
<g filter="url(#shadow)">
|
|
52
|
+
<rect x="70" y="88" width="160" height="56" rx="8" class="node"/>
|
|
53
|
+
<circle cx="100" cy="116" r="14" fill="#DBEAFE"/>
|
|
54
|
+
<path d="M94 116h12M100 110v12" stroke="#2563EB" stroke-width="2.4" stroke-linecap="round"/>
|
|
55
|
+
<text x="124" y="112" class="label">Telegram</text>
|
|
56
|
+
<text x="124" y="130" class="small">chat bot</text>
|
|
57
|
+
|
|
58
|
+
<rect x="70" y="160" width="160" height="56" rx="8" class="node"/>
|
|
59
|
+
<circle cx="100" cy="188" r="14" fill="#CCFBF1"/>
|
|
60
|
+
<rect x="94" y="180" width="12" height="16" rx="3" stroke="#0F766E" stroke-width="2.2"/>
|
|
61
|
+
<path d="M98 202h4" stroke="#0F766E" stroke-width="2.2" stroke-linecap="round"/>
|
|
62
|
+
<text x="124" y="184" class="label">ticlawk</text>
|
|
63
|
+
<text x="124" y="202" class="small">mobile app</text>
|
|
64
|
+
|
|
65
|
+
<rect x="70" y="232" width="160" height="56" rx="8" class="node"/>
|
|
66
|
+
<circle cx="100" cy="260" r="14" fill="#FDE68A"/>
|
|
67
|
+
<path d="M92 256h16M92 262h16M100 252v16" stroke="#A16207" stroke-width="2" stroke-linecap="round"/>
|
|
68
|
+
<text x="124" y="256" class="label">Web UI</text>
|
|
69
|
+
<text x="124" y="274" class="small">browser</text>
|
|
70
|
+
|
|
71
|
+
<rect x="70" y="304" width="160" height="56" rx="8" class="node"/>
|
|
72
|
+
<circle cx="100" cy="332" r="14" fill="#EDE9FE"/>
|
|
73
|
+
<path d="M94 326l6 6-6 6M102 338h6" stroke="#6D28D9" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
74
|
+
<text x="124" y="328" class="label">CLI</text>
|
|
75
|
+
<text x="124" y="346" class="small">terminal</text>
|
|
76
|
+
|
|
77
|
+
<rect x="70" y="376" width="160" height="56" rx="8" class="node"/>
|
|
78
|
+
<circle cx="100" cy="404" r="14" fill="#FFE4E6"/>
|
|
79
|
+
<path d="M94 398h12v12H94z" stroke="#BE123C" stroke-width="2.2" stroke-linejoin="round"/>
|
|
80
|
+
<path d="M97 395h6M97 413h6" stroke="#BE123C" stroke-width="2.2" stroke-linecap="round"/>
|
|
81
|
+
<text x="124" y="400" class="label">Custom app</text>
|
|
82
|
+
<text x="124" y="418" class="small">your surface</text>
|
|
83
|
+
</g>
|
|
84
|
+
|
|
85
|
+
<g filter="url(#shadow)">
|
|
86
|
+
<rect x="730" y="88" width="160" height="56" rx="8" class="node"/>
|
|
87
|
+
<circle cx="760" cy="116" r="14" fill="#FEF3C7"/>
|
|
88
|
+
<path d="M753 121l7-12 7 12M756 117h8" stroke="#B45309" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
89
|
+
<text x="784" y="112" class="label">Claude Code</text>
|
|
90
|
+
<text x="784" y="130" class="small">project agent</text>
|
|
91
|
+
|
|
92
|
+
<rect x="730" y="160" width="160" height="56" rx="8" class="node"/>
|
|
93
|
+
<circle cx="760" cy="188" r="14" fill="#DBEAFE"/>
|
|
94
|
+
<path d="M754 188a6 6 0 1 1 12 0a6 6 0 1 1-12 0" stroke="#1D4ED8" stroke-width="2.2"/>
|
|
95
|
+
<path d="M760 176v4M760 196v4M748 188h4M768 188h4" stroke="#1D4ED8" stroke-width="2.2" stroke-linecap="round"/>
|
|
96
|
+
<text x="784" y="184" class="label">Codex</text>
|
|
97
|
+
<text x="784" y="202" class="small">coding agent</text>
|
|
98
|
+
|
|
99
|
+
<rect x="730" y="232" width="160" height="56" rx="8" class="node"/>
|
|
100
|
+
<circle cx="760" cy="260" r="14" fill="#CCFBF1"/>
|
|
101
|
+
<path d="M752 260h16M760 252v16M755 255l10 10M765 255l-10 10" stroke="#0F766E" stroke-width="2" stroke-linecap="round"/>
|
|
102
|
+
<text x="784" y="256" class="label">OpenClaw</text>
|
|
103
|
+
<text x="784" y="274" class="small">local runtime</text>
|
|
104
|
+
|
|
105
|
+
<rect x="730" y="304" width="160" height="56" rx="8" class="node"/>
|
|
106
|
+
<circle cx="760" cy="332" r="14" fill="#FCE7F3"/>
|
|
107
|
+
<path d="M752 332c3-8 13-8 16 0c-3 8-13 8-16 0Z" stroke="#BE185D" stroke-width="2.2"/>
|
|
108
|
+
<circle cx="760" cy="332" r="3" fill="#BE185D"/>
|
|
109
|
+
<text x="784" y="328" class="label">opencode</text>
|
|
110
|
+
<text x="784" y="346" class="small">provider agnostic</text>
|
|
111
|
+
|
|
112
|
+
<rect x="730" y="376" width="160" height="56" rx="8" class="node"/>
|
|
113
|
+
<circle cx="760" cy="404" r="14" fill="#E0E7FF"/>
|
|
114
|
+
<path d="M754 398h12v12h-12zM751 401h3M766 401h3M751 407h3M766 407h3" stroke="#4338CA" stroke-width="2" stroke-linejoin="round"/>
|
|
115
|
+
<text x="784" y="400" class="label">Custom agent</text>
|
|
116
|
+
<text x="784" y="418" class="small">your harness</text>
|
|
117
|
+
</g>
|
|
118
|
+
|
|
119
|
+
<g filter="url(#shadow)">
|
|
120
|
+
<circle cx="480" cy="260" r="118" fill="url(#hub)"/>
|
|
121
|
+
<circle cx="480" cy="260" r="86" fill="#FFFFFF" fill-opacity="0.12" stroke="#FFFFFF" stroke-opacity="0.32" stroke-width="1.5"/>
|
|
122
|
+
<circle cx="480" cy="260" r="52" fill="#FFFFFF" fill-opacity="0.16" stroke="#FFFFFF" stroke-opacity="0.38" stroke-width="1.4"/>
|
|
123
|
+
|
|
124
|
+
<circle cx="480" cy="176" r="8" class="dot"/>
|
|
125
|
+
<circle cx="548" cy="212" r="8" class="dot"/>
|
|
126
|
+
<circle cx="548" cy="308" r="8" class="dot"/>
|
|
127
|
+
<circle cx="480" cy="344" r="8" class="dot"/>
|
|
128
|
+
<circle cx="412" cy="308" r="8" class="dot"/>
|
|
129
|
+
<circle cx="412" cy="212" r="8" class="dot"/>
|
|
130
|
+
<path d="M480 184v152M420 216l120 88M540 216l-120 88" stroke="#FFFFFF" stroke-opacity="0.65" stroke-width="2.6" stroke-linecap="round"/>
|
|
131
|
+
|
|
132
|
+
<text x="480" y="253" text-anchor="middle" class="hubText">ticlawk</text>
|
|
133
|
+
<text x="480" y="281" text-anchor="middle" class="hubSub">UNIVERSAL ROUTER</text>
|
|
134
|
+
</g>
|
|
135
|
+
|
|
136
|
+
<text x="480" y="465" text-anchor="middle" class="small">Bind sessions, relay streams, keep every side replaceable.</text>
|
|
137
|
+
</svg>
|