PTENES
Telegram gateway · durable queue

You send a line in chat. The heavy work happens automatically.

Telegram bot with a durable SQLite queue: runs single-step skills and multi-phase flows with state, a human gate, and recovery after a crash.

inemaccbot — Telegram gateway and durable queue
The skills and workflows registry is validated at boot: an invalid entry deliberately brings down the service.

An operator that doesn't lose work halfway through

The full path of a message. The two amber boxes are the most important boundaries: the gateway never does the work, and the runtime is the only thing that decides the next phase.

🗄️ Truly durable queue

SQLite in WAL mode, atomic claim, lease with heartbeat, and drain on shutdown. A kill -9 in the middle of a job, it never leaves the state undefined — nothing remains running with a live lease.

⏸️ Flows with a human gate

Playwright/aprovar) and selective resumption with /refazer.

🧩 New domain without code

A skill is a prompt + an entry in the registry. A flow is a repo with flow.json + prompts/. Neither one requires a line of TypeScript in the bot.

How it works

From the command in chat to the delivered file

The interpreter validates against

Telegram command→ allowlist + parse→ job in the queue (SQLite)→ worker complains (lease)→ agent runs→ artifact + chat notification

Five queues, different concurrency limits

io (10) · cpu (1) · texto (2) · render (1) · navegador (1). A heavy render doesn't block the text queue.

Skills × flow

A skill = one step, stateless—starting over from scratch is acceptable. A flow = multiple phases with state, when throwing away partial work would be absurd.

Boot sequence

Migrations → media root → recovery of expired leases → only then workers and bot. This is the order that makes the process recoverable after a crash.

Prerequisites

What it is

Node with TypeScript, a bot created on Telegram, and a .env with the five required variables. Without one of them, boot fails loudly and early, before starting any worker.

Node + dependencies

Install and run the tests before deploying anything.

# at the repo root
npm install
npm test

Telegram bot

Create the bot in @BotFather and save the token. The actual value never goes into git.

# .env (mode 600, outside Git)
BOT_TOKEN=…
ALLOWED_CHAT_IDS=123,456

State on disk

Queue database path, state root, and log file — the other three required settings.

QUEUE_DB=./inemaccbot.db
STATE_DIR=./estado
LOG_FILE=./inemaccbot.log
User guide · step by step

Start the service and operate it through chat

All commands below are real—the shell commands run in the repo, and the ones that start with a slash are typed in Telegram.

1

Install, test, and build

Prompt text is embedded in the workflow when it’s created. Editing the prompt today doesn’t change yesterday’s workflow—and

npm install
npm test          # vitest run
npm run typecheck  # tsc --noEmit
npm run build      # tsc -> dist/index.js
2

Start the process

In production via systemd, with the .env in the same working directory (deploy/inemaccbot.service).

node dist/index.js                       # directly
systemctl --user start inemaccbot       # as a service
3

Confirm that it’s alive

In the authorized chat. /ajuda lists everything; /skills e /fluxos are the two catalogs.

/ping
/ajuda
/skills   # one step, no state
/fluxos   # multiple phases, with state
4

Run a skill

The gateway validates who’s speaking (chat allowlist), the command becomes a job in the right queue, a worker claims the job with a lease, the agent runs it, and the notifier returns the result in chat. <skill>: <entrada> [| campo]*. Generic fields: livesN (destination), modelo=haiku, esforco=high.

transcrever: https://…                  # audio → text
explicativo: <assunto> | vertical       # 9:16 video
imagem: uma raposa ruiva na neve | ratio=16:9
5

Run a flow — always in shadow mode first

| sombra prints phase × target × queue × task and doesn’t queue anything. It's the cheap way to discover you were about to trigger 12 audiences by mistake.

/promoavatar <assunto> | sombra
/promoavatar <assunto> --alvo=jovens
/promoavatar <assunto> | alvos=mulheres | legenda
6

Monitor and release the gate

/status is the dashboard for OPEN flows; /completos lists the ones that finished. A#9, a#9, A9 e a9 are the same thing — numbers only (13) is always a job.

/status            # open flows
/status A#9        # phase × target detail
/fila              # running, pending, errors in 24h
/pronto A#9        # = /aprovar — opens the gate
7

Fix what failed without rebuilding everything

/refazer in a flow, resumes from the failed phase; for a single target, reruns that target. /cancelar removes it from the list without deleting anything already created elsewhere.

/refazer A#9 mulheres   # only the audience that failed
/cancelar A#9           # disappears from /status; the flow still exists
/furar j13              # puts a pending job at the front
8

Free up space with a dry run

Without the word confirmar at the end, it only shows what would be deleted and how much it would free up. The bot only touches what IT published inside of ~/projetos/output.

/espaco                  # disk by area (bot × skills)
/limpar A#8              # dry run
/limpar A#8 confirmar    # runs
9

Before restarting, check the queue

claude saiu com código 143 é 128 + 15 = SIGTERM: the job was killed by a service restart, not an agent error. A reel render takes 10–15 min — two consecutive restarts use up both attempts for the same job.

sqlite3 inemaccbot.db \
  "select id,fila,tarefa,status,flow_ref from jobs
   where status in ('queued','running');"
# Empty → restart whenever you want. With a render in flight → wait.
New domain

Add work without touching the bot

This is the design test: a new domain shouldn’t require a line of code in the bot. Choose between a skill and a workflow based on whether the work is partial.

A SKILL — one step, no state

Use this when “running it again from scratch” is acceptable. Write the prompt, declare it in the registry, and run the tests. A declared field must be used in the prompt, and a prompt variable must be declared — there are tests for both.

# 1. prompts/minhaskill.md — uses {{input}} and {{saida}},
#    and the agent's last line is RESULT: <path>
# 2. config/skills.json
{ "command": "minhaskill", "fila": "texto", "kind": "agent",
  "prompt": "prompts/minhaskill.md", "artefato_exts": ["txt"],
  "max_tentativas": 2, "timeout_segundos": 3600 }
# 3. npm test

One FLOW — multiple phases, with state

Use this when there’s partial work that would be absurd to throw away. It gains /status, /refazer selective, resumable, and frozen definition. The domain says WHO it’s for; the bot knows WHERE — never put a path in the flow.json.

# 1. repo ~/projetos/<nome> with flow.json + prompts/
# 2. flow.json: name, prefix (the P in P#16), versao_def,
#    targets and phases (id, scope, queue, kind, task…)
# 3. config/fluxos.json: { command, repo, descricao, exemplo }
# 4. check without spending anything:
/<fluxo> <assunto> | sombra

Every domain added to the catalog replies with help — not through discipline, but by design: those who understand write (HELP.md in the flow, <prompt>.help.md in the skill) and, if it didn't provide one, the help text is derived from the same record the bot uses to execute it. A test scans both catalogs and fails if any domain doesn't provide usable help.

promoavatar (A#)· promoavatar3 (C#)
State

What it does

Steps 0 through 5 completed, plus the domain workflows. v1 (inemaccvbot, mkivideos, mkitexto) is disabled.

Ready
Durable queueSQLite in WAL mode, lease with heartbeat, drain, atomic claim, recovery on boot.
Ready
Telegram gatewayChat allowlist, pure command parsing (without grammy), message truncation, notification when a job finishes.
Ready
Skills as an agenttranscribe · dub · explainer · course · demo · reel · reelinematds · historia · image.
Ready
Workflow engineState by phase and target, frozen definition, human gate, and resumption.
Open
Log out of TelegramWhatsApp, email, or chatbot: the gateway integration is already in place; what’s blocking it is chat_id to be INTEGER. Recommendation under review: don't replace it; add to it.
Open
Image and link as materialAccept an image and a link as flow inputs — analysis written, decision not made.
Outside
What’s intentionally missingPhase barrier, job preemption, global agent limit, multi-user support — each with a documented trigger for reconsideration.