telegram.day1.lifecycle

Telegram Listener Lifecycle Without a Daemon

A foreground lifecycle contract gives the Telegram listener durable start, stop, and lease files before any network intake exists.

telegram / channel-server / lifecycle / filesystem-first / matic

Thesis

A Telegram listener does not need to begin life as a daemon. The safer first contract is a foreground command that writes explicit listener state, owns a lease, and can be closed through a second command.

The listener-lifecycle work introduced that lifecycle contract. It did not poll Telegram yet. It did not handle stale leases yet. It did not try to hide process management behind a service manager. It gave the listener a durable shape that could be tested before any network behavior existed.

The Control Surface

The command shape is intentionally small:

PYTHONPATH=src python3 -m cli channels telegram listen /path/to/org
PYTHONPATH=src python3 -m cli channels telegram close /path/to/org

The first command starts the listener contract. The second command closes it. That sounds ordinary, but the important detail is where the truth lives. The truth is not in a hidden Python object or a terminal window. The truth is in files under:

<org-root>/.matic/channels/telegram/listener/

The listener writes:

  • state.yaml
  • lease.yaml
  • history.md

Those files are enough for a test, an operator, or a later runtime loop to know whether the listener is active, when it started, whether a lease exists, and what lifecycle events have happened.

State Is The Operational Contract

TelegramListenerState records the listener lifecycle in YAML. Through the source-layout contract it carries fields such as:

  • handle
  • status
  • started_at
  • stopped_at
  • inbox_count
  • lease_active
  • last_event

Later work extends this state with inbound offset fields, but the source-layout work already establishes the core rule: lifecycle status is durable and readable.

That matters because "the process is running" is not enough for Matic. Matic's runtime model needs work to be inspectable after the fact. A stopped listener should leave evidence. A failed duplicate start should be explainable. A later restart should have a file to read before it does any work.

Lease Before Background Magic

The lease file is the duplicate-start guard. When listen starts, it acquires a TelegramListenerLease. If another active lease already exists, the second start fails instead of silently creating a second listener.

That choice is deliberately strict. A Telegram listener can lose messages or duplicate work if two processes race over the same offset. The source-layout work does not yet process inbound updates, but it still sets the rule that only one active listener should own the channel lifecycle at a time.

The lease is also inspectable. It records active status, acquisition time, release time, owner process id when available, and a token. This is not a lock hidden in process memory. It is an operational record.

Close Should Mean Something

close is not a best-effort cleanup command. If there is no listener state and no lease, it raises an error instead of pretending work happened. If state or a lease exists, it finalizes the state as stopped, releases the lease, and records the close event.

That behavior gives operators a clean mental model:

  • listen creates an active lifecycle record.
  • duplicate listen is blocked by an active lease.
  • close stops an existing lifecycle record.
  • closing nothing is an error worth seeing.

This makes the CLI contract testable. The tests do not need Telegram secrets or network access. They can create a temp org root, run the server lifecycle, and inspect the files.

Why No Daemon Yet

Skipping a daemon was not an omission. It was a design choice.

A daemon adds questions that the source-layout work did not need to answer yet: supervision, signals, stale process detection, service installation, platform behavior, and deployment policy. The core lifecycle contract is smaller and more important. If the filesystem state is wrong, a daemon only makes the bug harder to see.

By keeping the source-layout work focused on explicit start and close semantics, the listener gets a stable base. The foreground-shell work can make listen remain foreground. The inbound-intake work can add Telegram intake. The recovery work can harden stop and recovery. Each layer depends on the same files instead of replacing the previous work.

The Result

After the source-layout work, the Telegram server has a real lifecycle vocabulary:

  • a package home for implementation code,
  • an org folder for runtime data,
  • a listener state file,
  • a listener lease file,
  • a listener history file,
  • and CLI commands that exercise the contract.

That is enough to prove the listener can be operated before it is useful as an inbound channel. In a filesystem-first system, that order is the point.

Waitlist

An idle user shouldn't mean
an idle org.

Matic runs autonomous organisations against long-horizon goals — a Charter at the root, named agents with their own memory, markdown state committed to git, and a mandatory learning loop after every engagement. Get on the list before the first orgs come online.

First-install accessArchitecture notesMilestones when they land

No spam. Product milestones, design decisions, and the thinking behind them — nothing else.

launchwaitlist@matic.sh

Architecture notes, first-install access, and milestones when they land. Never marketing.