# Create sandboxed rich-text telegram agents with a single config file

> Source: <https://github.com/montyanderson/007>
> Published: 2026-06-29 08:44:31+00:00

create sandboxed rich-text telegram agents with a single config file

needs [deno](https://deno.com/).

```
deno task start my-agent.yaml
```

this example is a research paper reader:

```
name: my-agent
telegram_token: "123456:ABC-DEF..."
anthropic_api_key: "sk-ant-..."
allowed_usernames:
  - your-username
model: claude-opus-4-8        # optional
system: |                    # optional — defines what the agent is
  you are a research paper reader assistant.
  download all (html) papers you read and store them.
  when embedding a figure, only use real image urls from arxiv.org.
sandbox:                     # optional — omit to deny all
  net:   ["arxiv.org"]       # hosts, not urls
  write: ["./papers"]
  env:   false
```

required: `telegram_token`

, `anthropic_api_key`

, `allowed_usernames`

. the
`system`

prompt is what turns the same engine into a paper reader, a maps
helper, a coding assistant, etc. — telegram formatting and the agent's sandbox
permissions are explained to it automatically, so `system`

only needs the
persona.

the yaml holds secrets. don't commit it.

the agent's one tool is `run_javascript`

, which runs in a deno subprocess. each
`sandbox`

entry maps to a deno `--allow-*`

flag on that subprocess:

`true`

→ allow (unrestricted)`[list]`

→ allow only those hosts/paths (e.g.`--allow-net=a.com,b.com`

)`false`

/ omitted → denied

omit the whole `sandbox`

block and generated js gets zero permissions. denied
operations fail with a deno permission error returned to the agent. the agent is
told its exact permissions in its system prompt, so it knows what it can and
can't do.

replies are sent with telegram's `sendRichMessage`

, so the agent's
github-flavored markdown renders natively: headings, **bold**/*italic*,
~~strikethrough~~, lists, task lists, blockquotes, `code`

, fenced code blocks,
links, footnotes, latex formulas (`$x^2$`

), tables, and media blocks
(`![](url)`

, including maps via `<tg-map .../>`

). a bad media url is stripped
and the message is retried so formatting never gets dropped wholesale.

- typing indicator while it works
- native rich-text replies (graceful fallback)
- per-user conversation history (in memory, resets on restart)
- streamed under the hood so long replies don't time out

```
deno task test
```


