Skip to content

Your agent asks permission on Telegram ​

Link Telegram once; from then on the agent can ask you, and you answer with a tap.

During setup:

bash
npx brynth init --telegram

or later, by asking your agent to call:

text
channel_add({kind: "telegram", label: "phone"})

You get a t.me link. Open it and press Start within 10 minutes; the code in the link works once. Brynth then asks the project's active channels (at first, your email) to approve the new channel. The channel is active only after that approval, so an agent alone cannot add a channel that approves its own requests.

2. Ask ​

text
ask_approval({
  action: "refund",
  summary: "Refund order 1042 (30 EUR)?",
  risk: "medium",
  amount: 30,
  wait_seconds: 45
})

You get a Telegram message with the summary and the buttons. If you answer within wait_seconds, the call returns the decision: approved, denied, modified or needs_context, with your comment. Otherwise it returns pending and the agent can carry on with other work.

risk: "high" requires details (up to 4,000 characters), shown to you before you decide. options adds up to 5 choices (40 characters each) besides approve and deny; picking one returns modified with the choice in decision. approvers: ["chn_…"] picks the channels; without it Brynth asks every active channel.

ask_human({question: "Which plan should the new customer get?"}) asks an open question the same way; its answer has status answered.

3. Resume after a later answer ​

When you decide after the wait, Brynth puts a request.resolved event in the inbox (source brynth, trust: "brynth"). Save the task state before asking and pass its id as state_ref:

text
state_save({task_id: "refund-1042", state: {order: 1042, step: "refund"}, note: "Waiting for approval"})
ask_approval({action: "refund", summary: "Refund order 1042 (30 EUR)?", state_ref: "refund-1042"})

Any later session, in any agent, finds the decision with inbox_list({type: "request.resolved"}), reloads the work with state_load({task_id: "refund-1042"}) and goes on. request_status({request_id: "req_…"}) reads a request at any time.

A request expires after expires_in (default 24h, from 1m to 7d) and its status becomes expired.

4. Let the policy decide ​

Rules decide which actions need you. This one sends every email outside your domain to Telegram:

text
policy_set({
  policy: {rules: [
    {match: {tool: "email_send", to_domain_not_in: ["acme.example"]}, effect: "require_approval", approvers: ["chn_…"]}
  ]},
  note: "Ask me before writing to customers"
})

A policy change is itself approved by a person before it applies. See Requests and policy.

CLI and skill released under the MIT License.