Issue
I've been intermittently pottering about with creating a telegram bridge for shelley.
At first I wanted to use the shelley client commands as a base
shelley chat [-c conv id] to start/continue a conversation
shelley read conv_id -wait to stream the responses
Unfortunately, for 2 reasons, I ended up having to poll sqlite in the background:
Tool use messages are a bit anemic,
eg. a bash call to list home dir appears in the chat export as:
## Assistant
**🛠️ Tool: `bash`**
{
"command": "ls -la ~"
}
<details><summary>Result</summary>
total 452
drwxr-x--- 29 exedev exedev 4096 Jul 16 12:11 .
drwxr-xr-x 3 root root 4096 Jan 8 2026 ..
....
...but shows up in the CLI output as as:
{"sequence_id":5,"type":"agent","tool_name":"bash","end_of_turn":false}
{"sequence_id":6,"type":"user","end_of_turn":false}
shelley client read -wait only lists up to the first "end_of_turn":true for conversations with multiple user inputs
First interaction
$ exedev@minikomi ~> shelley client chat -p "echo: FIRST RESPONSE"
{"conversation_id":"cJETWZL"}
$ exedev@minikomi ~> shelley client read -wait cJETWZL
{"sequence_id":1,"type":"system","text":"✂︎ system prompt here ✂︎","end_of_turn":false}
{"sequence_id":2,"type":"user","text":"echo: FIRST RESPONSE","end_of_turn":false}
{"sequence_id":3,"type":"agent","text":"FIRST RESPONSE","end_of_turn":true}
So far so good. Let's try a second interaction on the same conversation.
Second interaction
Sending the continuation:
$ exedev@minikomi ~> shelley client chat -c cJETWZL -p "echo: SECOND RESPONSE"
{"conversation_id":"cJETWZL"}
And the stream:
$ exedev@minikomi ~> shelley client read -wait cJETWZL
{"sequence_id":1,"type":"system","text":"✂︎ system prompt here ✂︎","end_of_turn":false}
{"sequence_id":2,"type":"user","text":"echo: FIRST RESPONSE","end_of_turn":false}
{"sequence_id":3,"type":"agent","text":"FIRST RESPONSE","end_of_turn":true}
Proposal
Sequence ID on send and continue from for read
It would be useful if chat returned a sequence ID identifying the exact user message that was accepted.
First interaction
$ exedev@minikomi ~> shelley client chat -p "echo: FIRST RESPONSE"
{"event":"accepted","conversation_id":"cJETWZL","sequence_id":2}
The bridge could then stream only messages created after sequence 2:
$ exedev@minikomi ~> shelley client read -wait -after 2 cJETWZL
{"event":"message","conversation_id":"cJETWZL","message":{"message_id":"<agent-message-id>","sequence_id":3,"type":"agent","text":"FIRST RESPONSE","end_of_turn":true}}
{"event":"done","conversation_id":"cJETWZL","sequence_id":3}
No system prompt or earlier history needs to be replayed.
Second interaction
$ exedev@minikomi ~> shelley client chat -c cJETWZL -p "echo: SECOND RESPONSE"
{"event":"accepted","conversation_id":"cJETWZL","sequence_id":4}
The new cursor makes the follow-up unambiguous:
$ exedev@minikomi ~> shelley client read -wait -after 4 cJETWZL
{"event":"message","conversation_id":"cJETWZL","message":{"message_id":"<agent-message-id>","sequence_id":5,"type":"agent","text":"SECOND RESPONSE","end_of_turn":true}}
{"event":"done","conversation_id":"cJETWZL","sequence_id":5}
Also if we need to catch up on past messages, we can use the last sequence ID seen and run the same command again without losing the response or replaying the whole conversation.
Waiting on chat itself
On sending a message chat -wait could also provide the common one-command form, so we don't have to send and then stream:
$ exedev@minikomi ~> shelley client chat -wait -c cJETWZL -p "echo: THIRD RESPONSE"
{"event":"accepted","conversation_id":"cJETWZL","message_id":"<user-message-id>","sequence_id":6}
{"event":"message","conversation_id":"cJETWZL","message":{"message_id":"<agent-message-id>","sequence_id":7,"type":"agent","text":"THIRD RESPONSE","end_of_turn":true}}
{"event":"done","conversation_id":"cJETWZL","sequence_id":7}
Tool interaction
Tool calls and results would be awesome to get in the stream too, so we can show them to the user:
$ exedev@minikomi ~> shelley client chat -wait -c cJETWZL -p "bash: ls -la ~"
{"event":"accepted","conversation_id":"cJETWZL","message_id":"<user-message-id>","sequence_id":8}
{"event":"message","conversation_id":"cJETWZL","message":{"message_id":"<agent-message-id>","sequence_id":9,"type":"agent","tool_calls":[{"id":"tool_123","name":"bash","input":{"command":"ls -la ~"}}],"end_of_turn":false}}
{"event":"tool_progress","conversation_id":"cJETWZL","tool_progress":{"tool_use_id":"tool_123","tool_name":"bash","output":"total 452\n"}}
{"event":"message","conversation_id":"cJETWZL","message":{"message_id":"<result-message-id>","sequence_id":10,"type":"user","tool_results":[{"tool_use_id":"tool_123","error":false,"text":"total 452\n...","display":{"workingDir":"/home/exedev"}}],"end_of_turn":false}}
{"event":"message","conversation_id":"cJETWZL","message":{"message_id":"<agent-message-id>","sequence_id":11,"type":"agent","text":"Done.","end_of_turn":true}}
{"event":"done","conversation_id":"cJETWZL","sequence_id":11}
We can use the output to report the tool call, progress, and result using tool_123, while still treating persisted messages as the replayable source of truth.
$ shelley-chat
❯ please run bash: ls -la ~
◆ Shelley
│
├─ 🛠 bash
│ $ ls -la ~
│
│ total 452
│ drwxr-x--- 29 exedev exedev 4096 Jul 16 12:11 .
│ drwxr-xr-x 3 root root 4096 Jan 8 2026 ..
│ ...
│
└─ ✓ completed
❯
Issue
I've been intermittently pottering about with creating a telegram bridge for shelley.
At first I wanted to use the
shelley clientcommands as a baseshelley chat [-c conv id]to start/continue a conversationshelley read conv_id -waitto stream the responsesUnfortunately, for 2 reasons, I ended up having to poll sqlite in the background:
Tool use messages are a bit anemic,
eg. a bash call to list home dir appears in the chat export as:
...but shows up in the CLI output as as:
{"sequence_id":5,"type":"agent","tool_name":"bash","end_of_turn":false} {"sequence_id":6,"type":"user","end_of_turn":false}shelley client read -waitonly lists up to the first"end_of_turn":truefor conversations with multiple user inputsFirst interaction
So far so good. Let's try a second interaction on the same conversation.
Second interaction
Sending the continuation:
And the stream:
Proposal
Sequence ID on send and continue from for
readIt would be useful if
chatreturned a sequence ID identifying the exact user message that was accepted.First interaction
The bridge could then stream only messages created after sequence
2:No system prompt or earlier history needs to be replayed.
Second interaction
The new cursor makes the follow-up unambiguous:
Also if we need to catch up on past messages, we can use the last sequence ID seen and run the same command again without losing the response or replaying the whole conversation.
Waiting on chat itself
On sending a message
chat -waitcould also provide the common one-command form, so we don't have to send and then stream:Tool interaction
Tool calls and results would be awesome to get in the stream too, so we can show them to the user:
We can use the output to report the tool call, progress, and result using
tool_123, while still treating persisted messages as the replayable source of truth.