Skip to main content
Glama

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
HERALD_CONFIGNoPath to the configuration file. Defaults to ~/.config/herald/config.toml.
HERALD_TELEGRAM_BOT_TOKENNoTelegram bot token. Used if token_env = "HERALD_TELEGRAM_BOT_TOKEN" is set in the platform section of the config; alternatively, the token is read from ~/.config/herald/telegram.token.

Instructions

Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.

This server publishes no instructions, or was last inspected before Glama recorded them.

Capabilities

Features and capabilities supported by this server

Protocol revision2025-11-25

CapabilityDetails
tools
{
  "listChanged": false
}
prompts
{
  "listChanged": false
}
resources
{
  "subscribe": false,
  "listChanged": false
}
experimental
{}

Tools

Functions exposed to the LLM to take actions

NameDescription
get_writing_rulesA

Read the current configurable writing style before composing a message.

batch_templatesA

List named batch templates and the default for a project. Roles and tags are metadata, never automatically added to client text. Template contents fill text and paths by part id. Custom part arrays are also supported.

preview_batchA

Prepare and structurally validate a message batch without sending or storing it. Read get_writing_rules first. Supply either parts or template/contents. Parts use unique ids and reply_to names an earlier part. Kinds: text, file, album, provenance. Roles and tags are arbitrary metadata. Provenance is generated, requires reply_to, and takes no text/files. No automatic signatures are added to other parts. All file paths and platform size limits are checked. validation=structure_only is NOT a claim of factual accuracy or client readiness; the AI must check those. Top-level reply_to may anchor one selected reply_part to a stored inbox message; this is separate from a part's named reply_to relationship.

send_batchA

Send an explicitly authorized batch after draft review and structural preview. Use one stable request_id per intended send. Reusing it returns recorded receipts, never resends uncertain/unfinished parts; a different plan with that id is rejected. Inspect complete and every part state: sent, unconfirmed, not_attempted. On error, stop and report exactly what is confirmed. Do not create a new id to retry blindly. All messages share one configured destination. Internal/provenance parts are not client copy. Signature metadata identifies the sending session, not text authorship. Top-level reply_to is a stored inbox key; reply_part selects the root batch part that answers it. Nested part reply_to still names an earlier part. Album parts accept 2–100 files and are split into linked Telegram groups of ten.

batch_statusA

Read persisted delivery receipts by request_id. Includes roles, tags, sender session metadata, Telegram message ids and named reply relationships for archives. unconfirmed may mean delivered: do not retry automatically after a crash or timeout.

batch_cleanupA

Delete completed batch ledgers older than the configured retention period, or the explicitly supplied positive number of days. Incomplete and unconfirmed attempts are always retained because deleting them would erase duplicate-send evidence. This removes local message text and file paths; it does not delete Telegram messages or attachment files.

list_destinationsA

List allowed projects and their default Telegram destinations.

send_textB

Send a free-form formatted message with provenance metadata.

Call get_writing_rules(project) before composing. HTML is the default. Use raw Telegram tags: , , , , , , ,

send_updateA

Send an explicitly requested structured internal update.

Call get_writing_rules(project) for the current writing style. The server renders summary and nonempty list fields as escaped Telegram HTML. Fields must remain within preset-specific character and item limits. Use send_text for free-form messages without those field limits.

send_client_copyA

Send copy-ready text addressed directly to the client.

Use this tool for explicitly requested named topics, so a manager can copy the body without understanding the project or rewriting it. Each topic title must be a concrete subject taken from the client message or current project, such as "Оплата" or "Фотографии". Never use fixed report headings such as "Проблемы", "Нужно решить", or "Вопросы". Preserve all subjects raised by the client that are inside the requested scope; brevity removes internal reasoning, not necessary facts.

Put concrete facts, proposals, and next actions in details. Address the client directly. Add question only when its answer blocks the next action now, and ask only the earliest unresolved dependency. Omit question when no answer is needed. Keep the visible topic self-contained. Use quotes only for an exact source or optional supporting detail: mode="visible" for a short source and mode="expandable" for longer material. A quote must not hide a required fact, action, blocker, or question, duplicate the visible body, or contain internal reasoning. title can identify the source or say "Подробнее". Do not shorten by a fixed word or item count. Keep all facts the client needs; the only hard content limit is Telegram's 4096 visible characters.

send_filesA

Send explicitly requested files as an album pack (2–100, split into Telegram groups of ten) or separate ordered messages (1–100). Use this only for a simple signed pack; use send_batch when files need multiple captions, roles/tags, clean client copy or a separate provenance reply.

Album auto accepts all photos or all documents; use kind=document for a mixed pack. All paths must be inside files.allowed_roots. One logical pack carries the caption and provenance once; later groups reply to the first. The caption must fit 1024 visible characters. Inspect complete, sent, unconfirmed, not_attempted. Never automatically retry unconfirmed files: they may have been delivered.

send_fileB

Send an explicitly requested local file or image with a concise caption.

The path must resolve under files.allowed_roots. kind=auto sends supported, small images as Telegram photos and everything else as documents. Use raw Telegram HTML in an HTML caption and keep it within the 1024-character limit.

notify_completionA

Send a completion notice only when the user requested notification.

Call get_writing_rules(project) before composing the summary. HTML is the default; pass raw Telegram tags. The tool preserves the supplied summary without adding a generic heading and appends the provenance signature.

list_inbox_sourcesA

List capture sources and their project ownership without reading messages.

inbox_statusA

Summarise what the capture daemon has buffered, without fetching content.

Check this before inbox_fetch: it reports volume per chat and the age of the oldest unprocessed message, so a range can be chosen deliberately. last_poll is the daemon's heartbeat - if it is hours old the daemon is down and Telegram will start dropping undelivered updates after about a day. taken_unarchived is separate from new messages. If attention_required is true, say clearly that messages were read/exported more than 24 hours ago but have not been confirmed in an archive; recover them with include_taken=true.

inbox_fetchA

Fetch buffered messages for reading and mark them as taken. This is not an archive operation and must never be described as importing or recording them.

since and until are ISO-8601 timestamps compared against the message date in UTC. Rows carry the forwarded-message origin, so a forwarded quote keeps its real author instead of the person who forwarded it. Fetching does not remove anything. For archival work use inbox_export, import that bundle, then call inbox_done with the imported keys and an archive_ref.

Set include_taken to see messages handed out earlier but never archived - that is how a batch interrupted halfway is recovered.

inbox_doneA

Mark messages as archived, which deletes their downloaded copies.

Call this only after the messages are in the archive with their hashes. Pass a non-empty archive_ref that identifies the recorded destination/batch. Herald stores it as opaque evidence and does not parse it or call the archive. If there is no archive reference, do not mark the messages done. The buffer copy of a file is redundant from that moment and is what actually grows on disk. Each key is {"chat_id": int, "message_id": int}. Rows survive for the configured TTL so a mistake stays recoverable.

inbox_exportA

Write a self-contained folder for a range, ready to import into an archive.

Prefer this over inbox_fetch whenever the messages are going into the archive: it copies the attachments next to inbox.json and rewrites their paths to be relative, which is the only form an archive will accept. Passing raw rows instead files every attachment as missing while the bytes are still on disk. Messages are marked taken; call inbox_done once they are recorded.

target must be a fresh directory. Set include_taken to rebuild a bundle for messages handed out earlier but never archived - that is the only route by which their attachments can still reach the archive.

watch_listA

List configured Watch profiles without registering a duty session.

watch_startA

Register this already-open AI session for deterministic Watch delivery.

The returned duty_id is required by every ordinary Watch read or write. Several profiles require an explicit primary_profile for #all replies. replace is an explicit takeover; it is never inferred. This registers only. It does not start polling. Retain monitor_command and use it with a verified host wake-up monitor, or keep watch_wait running in an active loop. A background shell alone does not wake the AI. Never report unattended listening unless a real addressed test reaches this session.

In Claude Code, Monitor is deferred: load it with ToolSearch("select:Monitor"), then give Monitor the returned command directly with stderr redirected to stdout and a 30-minute timeout. Do not use Bash run_in_background. Re-arm Monitor when its timeout fires.

In Codex, continue current project work by default. Poll cooperatively with watch_wait(timeout=0) at natural checkpoints and after blocking commands; do not report empty polls. Handle a delivery, then resume the interrupted task. Use a foreground wait only for explicitly requested pure duty. Ending the turn still ends polling.

Duties expire after 15 minutes without a monitor probe, AI poll, activity update or acknowledgement. Expiry releases the profiles and unfinished deliveries.

watch_activityA

Report this session's current activity: processing, waiting_user, or idle. Use while working and after replying if waiting for input. This is a self-report, not proof of polling. Only watch_wait updates last_poll_at. Refresh during long work when practical; stale activity is displayed as unknown, never assumed busy.

watch_waitA

Wait for and claim only the next delivery addressed to this duty_id.

This never returns another session's delivery, unaddressed messages, or a global queue. A timeout returns {"delivery": null}.

watch_inspectA

Explicitly inspect mine, unaddressed, or the gated all-delivery view.

This is read-only and never claims a delivery. all is refused unless watch.allow_inspect_all=true. Normal work uses watch_wait instead.

watch_replyA

Reply to a claimed Watch delivery through its configured Herald route.

The caller supplies no Telegram ids, project, route, agent, or model. Herald derives them from duty_id, delivery_id, and the validated profile. It tries a native Telegram reply first and uses a quoted fallback only after an explicit Telegram rejection. The delivery closes only after a send receipt.

watch_reply_batchB

Reply to a claimed Watch delivery with a named, idempotent batch. Herald derives the project, route, source reply, agent and model from the duty and profile. Use this for clean client copy plus a separate provenance reply, multiple text parts, files or albums. Use the same stable request_id to inspect an interrupted attempt; never create another id to retry an unconfirmed delivery. Check complete, every part state and delivery_state before reporting success.

watch_ackB

Close a claimed delivery when no content reply is required, or record failure.

watch_statusA

Show this duty's delivery counts, observed_state, activity timestamp, last_poll_at and monitor_at. Registration is not polling. monitor_alive proves only a recent companion probe, not AI wake-up. Stale activity is unknown; self-reported activity does not refresh last_poll_at. lease_age_seconds is the age of the freshest monitor, poll or activity signal; state=expired means the 15-minute lease ended and the profiles were released. Use this to verify a promised listener.

watch_stopA

Stop this duty and return its unfinished deliveries to their profiles.

Prompts

Interactive templates invoked by user choice

NameDescription

No prompts

Resources

Contextual data attached and managed by the client

NameDescription

No resources

TDQS

A3.7/5.0

Scored across 28 tools

Disambiguation4/5

The tool set is divided into distinct domains: watch duties, inbox capture, file/sending, and batch operations. A few closely related pairs like send_file vs send_files and watch_reply vs watch_reply_batch require careful attention to descriptions, but each tool has a clear purpose and overlaps are minimal.

Naming Consistency4/5

Most tools follow a predictable [resource]_[action] or [action]_[resource] pattern with strong prefixes like watch_, send_, and inbox_. Minor inconsistencies exist such as inbox_done vs watch_ack and get_writing_rules vs list_destinations, but the overall pattern is readable and coherent.

Tool Count3/5

At 28 tools, the count is on the heavier side, though justified by the server's broad scope covering watch lifecycle, inbox capture, batch sending, and file delivery. Some consolidation is possible (e.g., send_file could fold into send_files, watch_reply into watch_reply_batch), making the set feel slightly bloated.

Completeness4/5

The tool surface covers full lifecycles for its core workflows: watch duties from start to stop, inbox operations from status to archive, batch lifecycle from templates to cleanup, and multiple sending modes. Minor gaps like template editing and writing-rule modification exist, but these are plausibly managed externally.

Maintenance

ActivityActive
ResponsivenessNo issues