Chapters
On this page
DOC-04 / Technical reference · Chapter 05
Automata, crons and runs: non-conversational execution layer
This page describes the deterministic execution architecture of Synedre OS: Python facades, cron wrapping, automata registry and the boundary between runs and agent tasks.
Automata, crons & runs
This page describes the non-conversational execution layer of the Synedre OS harness: the Python facades, their cron wrapper, the automaton registry, the dual scheduling system (application-level scheduler + Linux crontab safety net), and the boundary between the run doctrine and the agent execution unit. Intended audience: engineers taking over the harness.
Security note: the actual crontab contains secrets in plain text (database passwords, bearer tokens). They are not reproduced here. This hardening debt — inline secrets in crontab — is flagged at the end of this page.
1. Mental model: agent (thinks) vs automaton (executes)
The harness separates two registers:
| Agent | Automaton | |
|---|---|---|
| Role | Thinks, decides, delegates (ReAct) | Executes a deterministic routine |
| Substrate | LLM persona (Claude / Mistral) | Python script from the facades directory |
| Table | Agents and personas table | Automaton registry |
| Trigger | Atlas spawn, Task tool, agent execution unit | Cron, CLI, application-level scheduler |
| Link between both | Automaton → owning agent join table; an agent may spawn an automaton or an agent execution unit. | |
An automaton does not "reason": it may call an LLM (content generation, classification) but its control flow is hard-coded. Reasoning lives in the personas and in Atlas; repeatable execution lives in the automata.
TRIGGER (email, cron, scheduler)
│
▼
┌──────────────┐ delegates ┌──────────────┐ spawns ┌──────────────┐
│ Atlas (run) │ ──────────► │ agent unit │ ───────► │ LLM CLI / │
│ registry │ │ (execution) │ │ Python facade │
└──────────────┘ └──────────────┘ └──────────────┘
▲ │
│ cron / scheduler ──────────┘
│ (scheduled automaton)
runs dashboard automaton registry + execution logs
2. The Python facades
The facades directory contains several hundred .py files (over 340 at the time of writing, growing continuously — the figure of 209 cited in a previous review from June 2026 is outdated). Not all of them are scheduled automata: the majority are facades (single entry point for a capability), some being shared libraries, manual tools, or one-off scripts.
The canonical classification registry lives in the database, not in the files. Two axes:
kind— technical nature:recurring— scheduled (cron or application-level scheduler)oneshot— triggered on demandtool— tool invoked by an agent or a skilllib— shared library, not directly executablemeta— meta-tooling (cron wrapper; the historical cron registration tool is archived, its implementation is no longer active)
caste— owning agent group. Eleven distinct values in the registry (as of 19 July 2026):- Vigies (26 facades) — audits, QA
- Oracles (22) — monitoring, reporting
- Scribes (21) — authoring
- Bâtisseurs (19) — build, provisioning
- Horlogers (17) — infra, session, backups
- library (16) — libraries
- Tisserands (15) — SEO, interlinking
- execution (10) — generic execution
- veille (3) — surveillance
- Cellériers (3) — finance, treasury, discounts
- phronesis (1) — strategic deliberation
⚠️ Casing is inconsistent (
executionlowercase vsVigiescapitalised) — normalisation debt to be addressed.
Functional taxonomy of facade families
| Family | Role | Notes |
|---|---|---|
| Atlas — orchestrator | Inbox → intent → spawn → dispatch pipeline. Includes facades for inbox polling, classification, spawn, dispatch, classifier calibration, client routing, and response composition. | ⚠️ Atlas-specific health and monitoring facades have been deleted (confirmed dead code, no dedicated replacement); generic monitoring remains covered by the SRE monitoring facades described below. |
| Audits | Drift detection, security findings, schema audit, nightly audit, sitemap audit, article audit, multi-tenant security reconnaissance. | ⚠️ An accessibility audit facade was deleted but is still called by the page audit facade (flag --a11y/--all) — broken call, silent FileNotFoundError caught locally. Blog cannibalisation detection now lives in the similarity library, consumed by the publishing engine and the fact-checker. |
| Backups | Database and file dump to object storage, monthly restore test. | Includes complementary shell scripts for low-level operations. |
| Brainstorm | Asynchronous jobs for idea generation, promotion, challenge, demotion, and narration; looping worker + one-off cron safety net. | |
| Blog / SEO | Content generation and hygiene, technical SEO, geolocation, sitemap. | ⚠️ The internal linking facade is archived, no longer active. |
| Email / inbox | Single send facade (no direct SMTP/IMAP access outside it), inbox synchronisation, search, lead scanning, email safeguard. | All client sends must go through the facade; mail credentials remain encapsulated. |
| Automated browser | Headful browser automation (residential worker), browser QA jobs, screenshots. | |
| Finance / billing | Bank synchronisation, statement import, recurring invoicing, payment reminders. | ⚠️ The generic reminder facade was absorbed into the billing package but is no longer wired to any cron or CLI. Only one client-specific reminder actually runs. A third-party accounting tool import is no longer active; only legacy fields remain in the database. |
| Brand / monitoring | Brand monitoring, technology watch, Google review synchronisation. | ⚠️ The newsletter monitoring facade is archived, no longer active. |
| Memory / learning | Vector indexing (pgvector), embedding synchronisation, semantic recall, memory metrics, pattern detection, nightly consolidation, post-mortems (scars). | |
| SRE / safeguards | Cost monitoring, runaway process detection, alerting, production write safeguard, founder notification. | |
| Doc — maintenance loop | Doc↔code drift detection, blind-spot coverage, deterministic dead-reference repair, autonomous deep regeneration, publication to synedre.com, organ graph and status (active workstreams), maintenance dashboard and public sync. | ⚠️ Three facades were mistakenly deleted by the pruning tool but are still called — see §7.1 for details. |
| Autonomy | Workstream seeder in automatic mode, triggered every 2 minutes but bounded to the daytime window; bootstraps the task worker pipeline. | See §8. |
| Libraries / infra | Database access, logging, environment loading, AI provider routing, log rotation, cron wrapper. | Shared building blocks, not directly scheduled. |
The Scheduled Task Wrapper Watchdog
Every scheduled automation is launched through a watchdog component that sits between the system scheduler and the target script. This watchdog is responsible for five main functions:
- Environment loading — at startup, it reads environment configuration files and injects variables into the process, never overwriting an already-defined variable.
- Automatic circuit breaker — it consults the consecutive error log. Beyond ten failures in a row, the script is automatically disabled and the system shuts down cleanly, without generating a log flood (this mechanism prevents several hundred spurious lines per day).
- Subprocess execution — the target script is launched as a child process with an isolated working directory and Python path. A 5-minute timeout applies by default; certain long-running automations benefit from an extended timeout of up to 30 minutes.
- Live self-repair — on error, the watchdog classifies the error message and attempts an automatic fix before relaunching the script:
- missing import → injection of the known import
- insufficient permissions on a log → redirection to an authorized directory
- missing directory → creation of the directory within the authorized scope
- missing Python module → installation into the virtual environment
- logging variable name conflict → automatic rename
- network error → three attempts with exponential backoff (2 s, 5 s, 10 s)
- Tolerant audit mode — certain automations are declared in "soft-fail" mode: a non-zero exit code is interpreted as an audit result (findings, not a crash), the error counter is reset, and the exit code is forwarded to downstream consumers.
Each error is recorded in the automation error persistence log, with the following fields: error type, full stack trace, automatic correction flag, detail of the applied fix, retry success, consecutive failure count, and disabled status.
Note on overlap protection: the watchdog does not acquire a system lock by default. Some automations manually add an exclusive lock for their single-execution modes. The majority of entries have no explicit lock — protection against concurrent executions relies on the combination of timeout and scheduling frequency.
The Run System
The "run" doctrine: a scoped execution by Atlas
A run denotes an execution driven by Atlas over a defined scope — the mothership or a client tenant. This scope is resolved automatically from the database: the technical context (relevant VPS, client, contact, mailbox) is loaded without manual configuration.
The runs table records for each run: an identifier, the triggering source, the trigger type, the scope, a title, the status, the type and identifier of the associated reference, and the start and end timestamps.
Two triggers are observed in production:
| Trigger | Source | Entry point |
|---|---|---|
email |
Atlas inbox | Emails forwarded to Atlas, classified by intent (run / question / project / noise) |
chat |
Hub console | Scope-aware console in the Hub, with scope selection and Atlas chat |
A third scheduled trigger (cron) is documented in doctrine but has not yet been observed in the database.
The agent execution task
The agent execution task is distinct from the run. It is the unit of work delegated to a specific agent. A run can generate one or more execution tasks when Atlas delegates to an agent.
Each task records: a code name, the assigned agent, a title, the prompt, the template used, the scope, the exit criteria, the status, the creator, the output log, the return code, token consumption, estimated cost, and the model used.
Status distribution observed in production (across approximately 750 tasks):
completed— majority (~52 %)failed— ~25 %done— ~21 % (status distinct fromcompleted; worth monitoring if the two diverge semantically)cancelled,pending,running— minority
The most frequently used templates are code (large majority) and audit, with a fraction of tasks having no declared template.
The agent task executor
A per-minute scheduled automation retrieves pending tasks, marks them as in progress, spawns the agent according to the template, streams the output into the task log, then marks the task completed or failed. It operates in two modes:
- Simulation mode (default) — no real spawn, used for testing.
- Production mode — agent spawn with permissions adapted to the template:
research→ read-only, Git commands and file exploration onlyaudit→ same + report writingcode→ extended permissions, confined to the declared task scope
Dynamic AI model resolution
Before spawning an agent, the executor dynamically resolves the AI model to use. It reads the model recommendation stored on the task (calculated by the token estimator at scheduling time), normalizes the alias (opus, sonnet, or haiku according to the detected tier), and passes this resolved model to the spawn. In the absence of a recommendation, the default model is sonnet.
Warning: until a recent fix, the model recommendation was calculated and stored for several thousand tasks, but never read during the actual spawn — all autonomous tasks executed in Sonnet, regardless of the recommended tier. This wiring is now active. The quality-check sub-run remains intentionally fixed at Sonnet.
The live validation gate before closure
For tasks carried by an agent with an infrastructure or frontend role, and whose project declares a target URL, the executor performs a real browser check just before marking the task done:
- A navigation agent (Chromium) visits the declared target.
- If the target responds with an error (502, blank page) → the quality validation result is downgraded to failure; the task is not closed, and a scar is recorded.
- If the browser agent is unavailable → the gate opens by default (fail-open) and the task is closed, but the event is logged; the downstream deployment gate remains, for its part, closed on doubt (fail-closed).
This gate corrects a false-positive pattern where an agent would declare a task complete (deployment, certificate) solely on the basis of its own declaration, without the target actually being reachable.
The Automation Verbose Execution Log
A dedicated log records each automation execution (approximately 124,000 entries and growing continuously) with: the automation name, environment, result, duration in seconds, number of steps, error and warning counters, step detail, and execution context.
This log is distinct from the watchdog crash log, which records only failures at the wrapper level, not the business-level results of automations.
The relationship between the various persistence tables is organized as follows:
Atlas Run (scoped)
└─ generates ─► Agent execution task ──log──► task output_log
Automation registry ──scheduled execution──► Automation verbose log
└─► Wrapper crash log (only)
Scheduling: two schedulers running in parallel
The built-in application scheduler
The mother ship exposes a native scheduled-task mechanism provided by its framework, enabled in experimental mode. Supervision tasks live in a dedicated layer belonging to the automaton engine, merged at startup — separate from the general-purpose task directory. The application container must be rebuilt after any scheduler configuration change for the changes to take effect.
History: the application scheduler experienced a multi-day outage in May 2026 and was subsequently restored as part of a reactivation workstream. The tasks listed below have been active since then.
A cross-cutting safeguard (guard) short-circuits certain tasks when a dedicated environment variable is not set in the container — allowing supervision cron jobs to be selectively disabled depending on the deployment context.
| Task role | Cron frequency | Guard |
|---|---|---|
| Outbound e-mail queue processing | Every 2 minutes | — |
| Availability monitoring (uptime) | Every 15 minutes | Internal context required |
| Dictionary / terminology watch | Every 30 minutes | Internal context required |
| Software dependency watch | Daily at 02:00 | Internal context required |
| Automated daily stand-up | Daily at 08:00 | Internal context required |
| SSL certificate monitoring | Daily at 09:00 | Internal context required |
| Brand watch | Daily at 12:00 | Internal context required |
Intentionally disabled tasks: inbox synchronisation and client e-mail synchronisation remain disabled. The IMAP client in use monopolises the Node.js event loop and causes cascading timeouts on the database engine. Re-enabling these tasks is contingent on the implementation of a non-blocking IMAP client, planned for a later phase of the same workstream.
Tasks present but not scheduled: several supervision modules exist (blog hygiene, page audit, sitemap watch, fact-checking, structured schema watch, etc.) but are not attached to any cron entry — they can be invoked manually or scheduled at a later stage.
The system crontab safety net
The server's Linux crontab constitutes the second scheduler, independent of the first. It accounts for the bulk of the scheduled workload and acts as a safety net: should the application scheduler go offline, critical automations continue to run. At the last review (July 2026), the crontab contains approximately 120 active lines out of a total of nearly 300. Commented-out lines form an archaeological record of the system's evolution — traces of deployment waves, experimental pauses, and documented deactivations.
Scheduled automations are grouped into several families:
-
Automations wrapped in a reliability envelope: the majority of recurring processes run through a Python wrapper that provides error logging and a self-repair mechanism. This family includes notably:
- availability monitoring (every 2 min);
- daily backups;
- automation and backup audits;
- bank synchronisation and recurring billing;
- Atlas inbox reading (every minute) and agent spawning (every 5 min);
- the documentation maintenance loop (every 6 h);
- the nightly system maintenance loop (daily at 05:00);
- the autonomy loop (every 2 min, self-limited by an availability window, cf. §8.1 — the file's docstring still references an outdated daily frequency);
- vector embedding synchronisation.
-
Python automations without a reliability envelope: several processes run as direct invocations, without centralised logging or automatic self-repair. This constitutes technical debt to be addressed. They include:
- knowledge graph indexing (every 15 min);
- job processing worker (every minute);
- skill indexing (every 15 min);
- deadlock detector (every 15 min);
- SRE and cost alerts (every 30 and 6 min respectively);
- drift detector (every 15 min);
- negotiation event extractor (every 2 min, with exclusive lock);
- inbound lead detection (twice daily);
- scar KPI refresh, Google review synchronisation, external document review processing;
- documentation publishing, backup restoration tests, log rotation, memory metrics, AI session indexing, skill proposal monitors and detectors, pattern detectors, daily summary.
- Brainstorming worker: launched at system startup in persistent loop mode (detached process). A cron safety net running every 2 minutes restarts it if the process is absent; a second net running every 3 minutes, with an exclusive lock, catches up missed passes.
-
Infrastructure scripts (shell and Node.js):
- site fleet and TypeScript dependency analysis (nightly);
- PostgreSQL and file backups to S3 object storage, for the mother ship and for several client VPS instances (staggered schedules from 02:00 to 03:45), with systematic failure notification;
- monthly restoration test from S3;
- vector brain synchronisation (every 30 min);
- workstream lock cleanup (every 5 min);
- Atlas lock watchdog (every 15 min).
-
Direct HTTP calls:
- outbound e-mail queue drain every minute via internal call — providing redundancy with the application scheduler task;
- session synchronisation every 5 minutes to an external endpoint.
⚠️ P0 debt: the session synchronisation HTTP call embeds an authentication token in plaintext within the crontab line. This constitutes a secret leak that must be remediated as a priority (see §7).
- Memory consolidation: monthly script for memory graph consolidation, with a long lock (10 min) to prevent concurrent executions.
- Open-source software quarantine: annual cleanup script run on a fixed date (mid-June).
Automations removed from the crontab: the founder notifier and the sector-watch module exist as active facades but have no scheduled entry — neither active nor commented out.
⚠️ Registry ↔ scheduling reconciliation (audit to be produced): the canonical automation registry classifies each automation by type (one-shot, recurring, reactive, etc.), but no automated mapping currently links recurring automations to their crontab line or to their application scheduler task. It is therefore impossible to determine how many automations are orphaned — registered as recurring but not actually scheduled. A cross-audit (registry × active crontab × application scheduler) remains to be produced.
The browser-worker: distributed automaton outside the datacenter
The browser-automaton family is the only subsystem where execution physically leaves the datacenter. Two distinct reasons for leaving the central server produce two egress topologies that must not be confused:
| Topology | VPS Component | Where the browser runs | What it processes | Mode |
|---|---|---|---|---|
| Outbound residential proxy | Server-side browser agent | Headless Chromium on the mothership VPS | IP reputation | Windowless + stealth mode |
| Remote headful worker | Remote browser worker | Headful Chrome on the residential machine | Browser fingerprint | Visible window, direct residential IP |
6.1 Why a residential headful Chrome rather than a VPS headless Chromium
An outbound proxy tunnel (described in the dedicated runbook) routes mothership traffic through a residential IP via a reverse SSH tunnel from a local machine. This is sufficient for sites that discriminate solely on datacenter IP reputation. An egress guard checks, before any launch, that the proxy is active and that the resolved outbound IP is not that of the central server — zero accidental egress through the datacenter.
However, Cloudflare Turnstile / managed challenge does not judge the IP: it judges the browser fingerprint (navigator.webdriver signals, plugins, window.chrome, WebRTC, headless markers). A headless Chromium behind a proxy retains a bot fingerprint even with a clean IP. Doctrinal consequence: classify the protection BEFORE coding the flow. If the site enforces Turnstile or managed challenge → headful Chrome on a residential machine is mandatory; headless stealth mode does not pass.
Hence the headful worker: real Chrome (visible window, stable distribution channel) runs on a residential Windows/Mac machine kept permanently on, with a direct residential IP. No proxy, no egress guard here: the correct IP is already in use, so Turnstile passes naturally.
6.2 Browser job queue and job lifecycle
The browser job queue lives in the database, with the following columns: job identifier, type (kind, varchar 32), payload (payload, jsonb, default {}), status (constrained to queued | running | done | failed), result (jsonb), error message (text), executing machine identifier (host), attempt count, start/end timestamps, creation and update dates. Indexes cover status alone and the pair (status, id) for ordered claiming.
Note: This subsystem is young and lightly used — the queue typically contains only a few active rows.
Inversion of control is the architectural key: the mothership VPS has no inbound access to the residential machine (NAT, dynamic IP). It is the remote worker that polls the mothership via outbound SSH. Full cycle:
[VPS — mothership] [Residential machine — Windows/Mac]
Atlas / skill / business automaton Browser worker --loop (daemon, 5 s interval)
│ enqueue │
▼ │ (1) git pull --ff-only (idle only) + restart if update
Enqueue CLI │ (2) SSH --claim --host <id> ─────────────────┐
│ INSERT status=queued │ │
▼ ▼ │
Job queue ◄──── FOR UPDATE SKIP LOCKED ── atomic claim status=running ◄────────────────────┘
│
│ (3) Dispatch by kind (strict whitelist)
│ Headful Chrome (visible window)
│ → Malt scraping: run + 2FA code retrieval via SSH
│ → e-commerce checkout: forced simulation mode
▼
Job queue ◄──── SSH --finish --status done|failed (result+error via STDIN JSON)
result jsonb / error │
│ temporary screenshot purge at end of run
Step details:
-
Enqueue (VPS) — The enqueue CLI rejects any
kindoutside the whitelist, validates the JSON payload, then inserts with statusqueuedusing randomised dollar-quoting (injection protection). -
Atomic claim (worker → VPS) — The worker picks the oldest
queuedjob viaFOR UPDATE SKIP LOCKED LIMIT 1, transitions it torunning, records the executing machine identifier, the start timestamp, and increments the attempt counter. Multiple workers cannot steal the same job. -
Dispatch (worker, headful) — The dispatcher routes by
kindto the business handler, without ever dynamically evaluating the payload (only typed business parameters are extracted:limit,quantity…). The whitelist of allowed types must remain synchronised between the remote worker and the VPS-side CLI — any addition of akindrequires editing both components. - 2FA code retrieval (worker → VPS → worker) — For scraping requiring strong authentication, the 2FA code never arrives on the remote machine via local email: the worker calls back to the VPS via SSH (dedicated sub-command), which reads the IMAP mailbox server-side and returns the raw code on stdout. The 2FA code is never logged in plaintext (masked in logs).
-
Finish (worker → VPS) — The worker transmits
{status, result, error}as a single JSON object on STDIN (never as a shell argument, which would cause breakage on newlines or quotes). The finish CLI writes the result (jsonb, randomised dollar-quoting), the error, and the end timestamp. -
Worker self-update — In loop mode, in the idle state only (never mid-job), the worker performs a
git pull --ff-onlywith a minimum interval of 60 seconds between attempts, then restarts itself viaos.execvif code has changed.
6.3 The SSH command portal (defence if the key leaks)
The worker's SSH key is installed on the VPS side with a command= directive pointing to a validation portal, paired with the options no-pty, no-agent-forwarding, no-X11-forwarding, no-port-forwarding. If the residential machine is compromised, the key does not open a free shell on the VPS.
This portal reads the SSH_ORIGINAL_COMMAND variable, splits it via shlex.split (never bash -c), and executes the command only if:
- the prefix is exactly that of the browser CLI interface (strict, immutable prefix);
- the sub-flag belongs to the allowed set:
--claim,--finish,--get,--enqueue,--malt-code; - each flag value satisfies its strict pattern — for example,
--idaccepts only an integer of 1 to 10 digits,--statusonlydoneorfailed,--kindonly an alphanumeric slug with hyphens.
Any unknown token or non-conforming value results in an immediate rejection with a stderr log. This is also why the worker never uses a cd … && prefix in its SSH commands: the portal requires a command beginning exactly with the expected prefix and manages the working directory itself. Worst case of a stolen key: polluting the job queue — not executing arbitrary code on the VPS.
⚠️ Personal data & screenshots — Results containing names or message excerpts are returned as jsonb in the private database, never logged in plaintext by the worker (only the counter is). Debug screenshots are purged automatically at the end of a run by the relevant business module, not by the worker itself; the worker merely logs their count. The --keep-screenshots option is reserved for local debugging. Additionally, a known latent bug exists: the browser job timeout (300 s) is not enforced in practice, meaning a browser job can remain blocked indefinitely — a fix is pending confirmation.
Documentation Self-Repair Loop
Since the workstream that introduced this layer, the system has a coherent pipeline that measures the gap between its own documentation and its code, then corrects it autonomously with guardrails. This loop is the most recent and most intricate automation layer in the architecture.
Pipeline Architecture
Active unresolved regression (detected during code review, 2026-07-19). A prior pruning workstream deleted three components incorrectly classified as inactive, even though they are still invoked by the nightly orchestrator. Since that date, three pipeline steps fail every night with return code rc=2 (file not found). Because that code is not interpreted as a crash by the orchestrator (which only treats negative codes as crashes), the failure does not surface as a dedicated alert — it appears only in the output summary. The affected steps are marked ⚠️ DEAD in the diagram below. See § 7.4, § 7.10, § 7.14 and the "Flagged Debt" section for details.
The nightly orchestrator (cron 5 h) chains twelve steps in the following order:
nightly-orchestrator (cron 0 5)
┌─ perceive → doc↔code drift detector (fidelity mirror, read-only)
├─ coverage → blind-spot detector (documentation completeness)
├─ anatomy → organ drift detector ⚠️ DEAD — rc=2
├─ organ-graph → inter-organ edge calculator (live)
├─ repair → dead-reference repairer (deterministic)
├─ regenerate → deep rewrite engine (gated, LLM)
├─ propose → staging and brief engine ⚠️ DEAD — rc=2
├─ publish-doc → chapter publisher (machine gates, auto-activation)
├─ publish-organs → organ publisher ⚠️ DEAD — rc=2
├─ re-perceive → doc↔code drift detector (re-measurement post-repair)
├─ health → health summary aggregator (on the FINAL state of the tick)
└─ publish → sanitized public exporter (snapshot → synedre.com)
drift detector : cron 0 */6, independent (runs on its own schedule)
mechanical repairer : cron 10 */6, independent (NOT orchestrated by the tick)
external review : cron */30, independent
The health summary (health) is executed at the end of the tick, after the drift re-measurement (re-perceive), and not immediately after coverage. This reordering ensures that the health report published on synedre.com reflects the state after repair and regeneration, not the state at the start of the night.
The Mirror — Doc↔Code Drift Detector (step: perceive)
Cron: every six hours (via wrapper). Principle — strictly read-only: the component never writes to code or documentation; it records only its measurements in the tracking tables.
Three types of drift are measured:
- Code more recent than the doc — the linked source file was committed after the documentation file: the doc describes a stale body.
- Dead reference — the documentation file cites a file (with line number) that no longer exists in the repository.
- Stale public chapter — the version published on synedre.com lags behind the internal documentation file (non-matching SHA-256 fingerprint).
The component is idempotent: one measurement row per chapter per day. It returns code 0 if no drift is detected, 1 otherwise.
It is called twice by the nightly orchestrator: at the perceive step (start of tick) and at the re-perceive step (end, after repair and regeneration) — the second measurement feeds the health summary on the final state.
The Blind-Spot Detector (step: coverage)
Launched immediately after the mirror. Checks the completeness of the documentation — "is there a part of the system I never mention?" — complementing the mirror, which checks fidelity — "is what I say still true?".
Method: set difference.
- Documentable body — the set of recognized components and tables in the system.
- Current coverage — those named in at least one internal documentation chapter.
- Blind spots = Documentable body − Coverage, grouped by family.
An isolated uncovered component is not necessarily problematic; a group of uncovered components from the same family is a candidate for a new section or chapter (created by the deep rewrite engine in creation mode). Read-only component: edits no files.
Returns code 0 if no blind spots, 1 otherwise. The coverage dimension is consolidated into the health summary.
The Organ Drift Detector (step: anatomy) ⚠️ DEAD
Intended role: status proprioception of organs — compares the declared status of each organ in the public registry against the active/inactive state of its underlying automation, and reversibly self-corrects (an organ whose automation is inactive is downgraded from built to partial). Asymmetry rule: this component never raises a status automatically — elevating an organ's status remains a deliberate human action.
⚠️ Component not found in the repository. This script was deleted by the pruning workstream (2026-07-17), incorrectly classified as inactive while the nightly orchestrator continues to invoke it at the anatomy step. Since that date, the step fails consistently (rc=2), with no dedicated alert. The component can be restored from the system trash within the 30-day grace window; the validity of that window should be confirmed at the time of reading.
The Inter-Organ Edge Calculator (step: organ-graph)
Derives and maintains edges linking organs to one another, in two classes:
- Derived edges — provable by a deterministic query, recalculated on each run (idempotent).
- Manual edges — conceptually true flows not provable by a single query; seeded once, never overwritten.
Edge type taxonomy:
| Type | Meaning |
|---|---|
flux | Produces or routes a flow |
compose | Is part of a larger whole |
gouverne | Frames without owning |
veille | Monitors |
contraint | Structural rule |
declenche | Initiates a cycle (impulse, not continuous) |
Guardrails:
- Verification that the target database is the internal database (anti-leak) — any write to another target is blocked.
- Rejection of labels implying volition or control: the graph describes plumbing, never intentionality.
- Blocking if a prohibited edge reappears.
- Dedicated kill-switch, independent of the orchestrator's global kill-switch.
--test-idempotencymode: two consecutive runs produce an identical state.
The Dead-Reference Repairer (step: repair)
Invoked by the orchestrator at the repair step in live mode with commit, before LLM rewriting. Bridges the gap between the mirror (which diagnoses dead paths) and the rewrite engine (which corrects prose but has no knowledge that a file has moved): the resolution is deterministic, with no possibility of hallucination.
For each dead reference in an internal documentation file, the component attempts to locate the actual file by its base name:
- Single result (certain) → the path is rewritten in place.
- No result (file deleted) → flagging + report + notification to the founder (human decision required).
- Multiple results (ambiguous) → flagging + report, no automatic rewrite.
Guardrails: edits only internal documentation files — never code, never system instructions, never public chapters. Idempotent. One commit per run (a single git revert undoes everything). Returns 0 if nothing to do or everything resolved, 1 if unresolvable references remain.
To be distinguished from the independent mechanical repairer (§ below): this component fixes references only (deterministic, triggered by the orchestrator); the mechanical repairer attempts other structural corrections and runs on its own cron.
The Health Summary Aggregator (step: health)
Invoked by the orchestrator at the end of the tick, after the re-perceive step. Aggregates five dimensions without modifying any of them:
| Dimension | Source | What it measures |
|---|---|---|
| Proprioception | Drift tracking table | Doc↔code gap |
| Coverage | Coverage table | Share of the system never documented |
| Debt | Open P0/P1 backlog | Volume of flagged technical debt |
| Learning | Scar KPI view | Signal of resolved incidents |
| Automations | Cron error log | Health of scheduled tasks |
Writes an idempotent snapshot to the health table (one row per dimension per day) and generates a daily report item. Returns 0 (OK), 1 (warning), or 2 (critical).
The Mechanical Repairer (independent of the tick)
Cron: every six hours, offset by ten minutes relative to the mirror. Runs independently of the nightly orchestrator. Edits only internal documentation files — never code, never system instructions, never public chapters.
Safety rule: a dead reference is corrected only if its base name matches exactly one git-tracked file. Zero candidates (component deleted) or two or more candidates (ambiguity) → proposal sent to the technical channel, with no automatic modification. Reversible: one commit per run. Capped (--max) and equipped with a kill-switch. Test mode (dry-run) by default; the --live flag is required to write.
The Deep Rewrite Engine (step: regenerate)
Called by the orchestrator with a wall-budget (default: 4,500 seconds). Opens a headless Claude session that: (a) rewrites the internal documentation file by reading the actual code, (b) directly produces the public bilingual FR+EN HTML version with its metadata in a temporary directory. The internal documentation file is committed, then an anti-leak gate is applied before any public staging.
The Staging and Brief Engine (step: propose) ⚠️ DEAD
Historical role (until 2026-07-17): launched after the deep rewrite, this component re-staged chapters whose internal documentation file was ahead of the published version, with an independent anti-leak gate (any chapter leaking sensitive data was marked "BLOCKED") and a regeneration brief for ambiguous cases.
⚠️ Component not found in the repository. Deleted by the pruning workstream (2026-07-17), incorrectly classified as inactive while the orchestrator continues to invoke it at the propose step. Since that date, no chapter is re-staged automatically through this path. The main publication path (§ chapter publisher below) remains active. Restorable from the system trash within the 30-day grace window; to be confirmed.
The Nightly Orchestrator (cron 5 h)
Cron: daily at 5 h (via wrapper). Runs the twelve steps described in § Architecture in order, under global guard:
- Execution lock — prevents any overlap if a previous run is still in progress.
- Database kill-switch — if the orchestrator itself is marked inactive in the automation registry, the tick stops immediately.
- Configurable wall-budget for the deep rewrite engine (default: 4,500 s); the tick's global timeout is the budget plus 1,800 s.
- Step isolation — if a step fails, the tick continues and records the failure. A non-zero return code (1 or 2, including the three dead steps) is treated as a status, not a crash; only a negative code (exception in the control loop itself) counts as a crash.
- At the end of the tick: calls the public exporter to push a sanitized snapshot to synedre.com.
Available options:
python3 -m <nightly-orchestrator> [--dry-run] [--no-deep] [--deep-budget-sec N]
The Sanitized Public Exporter (step: publish)
Called at the end of the tick. Reads data from the maintenance loop out of the internal database (read-only), sanitizes it (removal of any client name, IP address, secret, or internal path), then pushes a JSON snapshot to the flux table on the synedre.com VPS — idempotent update keyed on the snapshot date, with automatic table migration on first run. Feeds the maintenance dashboard accessible from the public documentation section.
The Chapter Publisher (step: publish-doc)
Two invocation paths:
- Autonomous cron at 3:30 h — direct execution with automatic activation and a per-run chapter limit.
- Nightly orchestrator at the publish-doc step — same parameters. The tick is thus self-contained without depending on the separate cron. This is currently the only effective re-staging path, since the staging and brief engine is out of service.
Mechanism: detects chapters whose source SHA-256 fingerprint no longer matches the published version, re-stages them in the pending-chapters table (secure transport to the public database), with a multi-layer regex anti-leak pre-gate.
Publication to live: via deliberate manual activation or via automatic activation — pending chapters that pass all machine gates (regex anti-leak, public registry § VII filter) are published without human action; rejected chapters remain pending and trigger a notification to the founder.
The Organ Publisher (step: publish-organs) ⚠️ DEAD
Historical role (until 2026-07-17): synchronized organ metadata (emoji, name, status, position) from the internal database to synedre.com, with an anti-leak scrub gate before writing. Explicit asymmetry contract: emoji, name, status, and position are propagated deterministically and automatically; the meaning of an organ (description, translation, qualitative dimensions) is never propagated automatically.
⚠️ Component not found in the repository. Deleted by the pruning workstream (2026-07-17), incorrectly classified as inactive while the orchestrator continues to invoke it at the publish-organs step. Since that date, the status, name, and emoji of organs displayed on synedre.com are no longer automatically resynchronized from the internal database. Restorable from the system trash within the 30-day grace window; to be confirmed.
The External Review (independent of the tick)
Cron: every thirty minutes. Dequeues reviews submitted by the human operator (response from an external model), evaluates them via a sandboxed Claude session with anti-injection delimiters, selectively parses the JSON verdict (overall validity, injection-attempt detection). If the review is deemed valid → signal only (note in the daily report), with no inline regeneration. Regeneration is consumed by the nightly orchestrator on its next tick — a decoupling introduced to prevent a timeout from killing computation mid-run.
Autonomy Tick
Role and cadence
The autonomy tick is a cron automaton that runs every two minutes in active mode (--live). Its role is to bridge the cold-start of the autonomy pipeline: the task-processing engine self-chains within a running job, but nothing primes the pipeline when an automatic-mode job has pending tasks and no active run. The tick detects these dormant jobs and inserts a run in pending status for the next eligible task in each affected project.
Historical note: the inline documentation for this automaton and its CLI label still describe an older daily cadence at a fixed time. The actual doctrine — a frequent tick self-limited by a configurable time window — takes precedence over these outdated references.
Autonomy window and quiet hours
Even in active mode, the tick triggers no seeding outside the day's autonomy window, which is read from the database and editable via the /fenetre-autonomie command. Outside the window, the automaton silently reverts to observation mode. Manual steering targeting a specific project bypasses this window — an explicit action reserved for the founder.
Triggering safeguards
- Cost ceiling: if the cumulative cost of a project reaches 100 % of its allocated budget, the project is frozen and no run is seeded.
- Environment kill-switches: two environment variables allow the automaton to be fully neutralised (one disables global automatic mode, the other disables this tick specifically) — when either is set, the tick becomes a complete no-op.
- Deployment kill-switches: two separate variables allow the automatic deployment and release steps to be disabled independently, reducing the tick to a pure signalling role with no action taken.
Automatic deployment and release
In active mode, the tick can trigger the ./deploy and ./ship commands. The decision is made site by site according to each client's configuration in the database. By default a client is eligible; it can be explicitly excluded. For unattended nightly shipping, an additional condition applies: a green QA proof must exist — without it, the automaton emits a signal but does not execute the ship.
Post-ship safety net
After each deployment, application health is verified via an HTTP gate on the published port. If the check fails, the previous version is automatically restored from the local backup maintained for this purpose. A legacy health-check script exists in the repository but is explicitly marked as dead code and deprecated — it is not called anywhere in the active code paths.
For autonomously triggered ships, the automaton systematically retains the local backup of the previous build, even after a deployment deemed healthy by the HTTP gate. This behaviour allows manual rollback of a functionally defective build that a liveness check alone cannot detect. Manual ships retain the standard behaviour (backup purged after health confirmed).
Immutable protection floor
Certain clients are defined in source code as unconditionally excluded from automatic shipping, independently of any database configuration. This check is performed first, before any database read. The reason: the tick runs via a system subprocess, outside any interactive session — the protection hooks that filter interactive invocations never see these calls. A single corrupted row in the database would have been sufficient to bypass the protection had this floor not existed. This floor is the Python mirror of the session hooks: the same list of protected targets, across two independent code surfaces.
Safeguards & operations
- Circuit breaker: a cron wrapper automatically disables an automaton after 10 consecutive crashes, recording the state in the database.
- Daily audit: a nightly audit automaton re-reads error logs and automaton logs to produce a health report.
- Cost and runaway monitoring: three scheduled automatons (every 6, 15, and 30 minutes respectively) monitor costs, detect runaways, and emit SRE alerts.
- Backups & restore tests: nightly dumps are sent to remote object storage (primary database, files, remote client databases); a monthly automaton tests the effective restoration of these backups.
- Automatic unblocking: an automaton scheduled every 15 minutes detects stuck runs and restarts them, up to 4 attempts, with a dedicated kill-switch.
- Documentation loop: a drift detector, an automatic corrector, and a nightly maintenance automaton compose the documentation self-repair cycle (detailed in the preceding section).
Reported technical debt
- ✅ Dead cron cleaned up: a URL-leak audit automaton was removed without a replacement. The corresponding crontab entry — which was failing silently because it did not go through the standard wrapper — has been removed. No facade replaces it at this time; to be recreated via the wrapper if the need arises again.
- ⚠️ Plaintext secret in crontab: a crontab entry embeds an authentication token directly in the command line. To be migrated to reading from the environment file, following the pattern already used by other entries (database password read via shell variable substitution).
-
⚠️ Double execution of the email queue: an email queue processor is triggered both by the application server (every 2 minutes) and by an HTTP cron call (every minute). The redundancy is harmless thanks to a queue-side
LIMIT, but should still be cleaned up. -
⚠️ Case inconsistency in the automaton table: the
kindfield (execution type) has values with inconsistent casing across existing records. A normalisation debt to address. -
⚠️ No generic lock in the cron wrapper: automatons not protected by
flockmay overlap if their execution time exceeds the trigger interval. - ✅ Fixed: this page incorrectly stated that the autonomy tick ran in observation mode only. This reference was outdated — active mode has been wired into the crontab since doctrine v3, the tick runs every 2 minutes and self-limits via the configurable autonomy window (see preceding section).
- 🔴 Pruner regression (unalerted): the nightly maintenance loop calls three scripts that were deleted during a previous cleanup project. The corresponding steps fail every night with a return code indicating a missing resource, silently absorbed (only negative codes are counted as crashes). No alert has triggered. Concrete consequences: re-synchronisation of documentation component status to the public site no longer occurs, and documentation re-staging now only goes through the standard publication path. A fourth zombie script, called by the page audit automaton, belongs to the same regression class. A 30-day grace window since deletion allows restoration if the need is confirmed; otherwise, the corresponding call sites must be cleanly removed.
- ⚠️ Latent bug on browser job timeout: the timeout constant defined in the browser worker is not effectively applied — a browser job could theoretically remain pending indefinitely. To be confirmed and fixed.