Chapters
On this page
DOC-05 / Technical reference · Chapter 01
Agentic harness overview
The harness transforms a request (email, console, cron) into a deployed action by chaining intent classification, pseudo-TTY LLM spawn, two-level quality validation, and a learning loop — with no business state stored outside the database.
1. What the harness is
The "harness" is the set of mechanisms that transforms a request (a forwarded email, a message in a control console, a scheduled trigger) into a deployed action (committed code, a response drafted for human review, an updated website), with no business state stored outside the database.
Three principles structure it:
- Database-first. The PostgreSQL database is the single source of truth for all business data. Documentation files carry only operational guides, architecture diagrams, and doctrines. Every registry (servers, clients, missions, agents, learning journals, executions) lives in a table.
- Deploy/publish asymmetry. Staging environment updates are triggered automatically by the system. The final production release is a manual, human-exclusive action. The system never publishes to production on its own.
- Governance through guardrails. Mandatory antivirus checks before opening any attachment, a single email-sending facade subject to human approval, secret anti-leak protections, and a seven-step procedure for creating structured missions. Any violation triggers a priority architectural debt.
The harness serves a private control cockpit — distinct from the public e-commerce products and client-specific configurations. This page covers only the harness itself.
2. Real topology
Three execution layers all communicate with the same PostgreSQL schema, but through different transports:
- The cockpit (standalone Nuxt 4 Nitro application) — the control interface. Database access via a postgres-js pool with a MySQL-to-PostgreSQL translation adapter working at query time: positional parameter substitution, schema qualification on business tables, conversion of
INSERT IGNORE,DATE_SUB/DATE_ADD,TIMESTAMPDIFF,IFNULL, and camelCase aliases. Some MySQL constructs are not automatically converted (ON DUPLICATE KEY UPDATE,LAST_INSERT_ID(),GROUP_CONCAT,FIND_IN_SET,DATE_FORMAT,CURDATE()) and must be ported manually. The application is composed of 27 independent modules. - The Python automation layer (236 facades) — orchestration, automation, memory, audits, email, deployment. Database access via a dedicated database container, routing queries through sub-processes.
- Scripts and scheduler — deployment wrappers, LLM engine spawn via pseudo-TTY, attachment extraction, backups, regression tests. The scheduler built into the Nuxt application has been offline since May 2026; scheduling relies exclusively on the host machine's Linux crontab (69 active entries).
REQUEST
forwarded email ──┐ ┌─── control console
agentic mailbox │ │ (scoped to cockpit | tenant)
▼ ▼
┌─────────────────────────────────────────────────────┐
│ PYTHON LAYER — 236 facades │
│ Orchestrator: poll + classification + spawn │
│ Execution: task worker, ReAct cycle │
│ Memory / audits / email / deployment │
│ Headless LLM invocation via pseudo-TTY │
│ (never direct subprocess) │
└──────────────┬──────────────────────┬───────────────┘
sub-process DB │ │ SSH + container
▼ ▼
┌────────────────────────┐ ┌──────────────────────────┐
│ POSTGRESQL │ │ COCKPIT (Nuxt 4) │
│ single schema │◄──┤ control interface │
│ 271 tables + 18 views │ │ postgres-js pool │
│ business tables │ │ MySQL→PG adapter │
│ legacy shim views │ │ 27 modules │
└────────────────────────┘ └──────────────────────────┘
▲
scheduler │ Linux crontab (69 entries)
(Nitro │ shell / Node scripts
offline) │
┌──────────────┴──────────────────────────────────────┐
│ SCRIPTS AND CRON — deploy, hooks, backups │
│ Asymmetry: staging deploy = automatic │
│ production publish = human action │
└─────────────────────────────────────────────────────┘
Key architectural pitfalls to keep in mind:
- The PostgreSQL schema is distinct from the default
publicschema; explicit schema qualification is required on all queries. - Twelve tables in the agent registry are actually views that wrap the underlying physical tables — a legacy of a progressive migration. Read from the views; write to the physical tables.
- A single "mission" entity is split across legacy tables (control data) and cockpit tables (execution tracking).
- The cockpit is standalone: it does not extend the e-commerce codebase. Real security relies on network infrastructure (SSH tunnel and nginx filter gate); a middleware auto-injects an operator session internally.
3. Complete request lifecycle
The canonical path: "email → deployed action." Two entry points feed the same orchestration engine: the agentic mailbox poll and the control console.
(0) INGESTION
An operator forwards an email to the agentic mailbox
│ scheduler */1 min — IMAP poll (SEARCH UNSEEN)
▼
Record in database (raw) ──► agentic queue (status='received')
│
(0b) ANTIVIRUS SCAN (if attachment — scan-first P0 doctrine)
│ ClamAV analysis + heuristics (malicious PDF, Office macros, executables)
│ verdict ∈ {clean, suspect, blocked} ; verdict ≠ clean ⇒ classification BLOCKED
▼
(1) CLASSIFICATION (LLM via unified AI facade, strict enum, anti-injection)
classified_intent ∈ {run, chantier, question, noise, negociation, conseil}
│ materializes at most 1 row in the corresponding table
▼
(2) SPAWN + ORCHESTRATION (scheduler */5 min, offset 120 s after classify)
Python orchestrator
│ PostgreSQL advisory lock (anti-double-spawn)
│ spawn LLM engine via pseudo-TTY (node-pty, stream-json):
│ context isolation between spawns (zero cross-run leakage)
│ configured model, controlled permissions mode
│ optional toolset restriction (e.g. QA validator read-only)
│ configurable timeout (default 15 min, extendable to 40 min by caller)
│ ⚠️ CLI argument order: varargs arguments must precede flags
│ ⚠️ log stream must close AFTER the exit event is emitted
│ ⚠️ stdout pipe must be drained before process exit
│ the LLM engine writes a JSON result file, then exits
▼
Post-spawn handler
├─ no-code branch (run/question/negociation) → summary email → 'actioned'
└─ code branch (chantier) → automatic staging deployment
└─ Two-level quality check per route:
Level 1 — HTTP request (status + error pattern detection,
optional SSH bypass for nginx filter gate)
Level 2 — Playwright chromium headless browser
(console errors, page errors, screenshot)
Noise filters: 401 and ERR_HTTP2 ignored
on basic-auth-protected staging environments
├─ OK → summary email to operator → status='actioned'
└─ FAIL → re-spawn (max 3 iterations) then human escalation
▼
(3) STRUCTURED MISSION (if intent=chantier, see dedicated documentation)
7-step procedure: agent audit → mission brief → recruitment ≥2 agents
│ atomic creation: mission + work packages + tasks in one transaction
▼
AGENT EXECUTION: task worker (*/1 min) or ReAct cycle
│ status cascade task→work→mission (max 1 level); QA team if recruited
▼
mission → 'test' (staging review, operator validation) ── manual ──► publish → 'done'
▼
(4) LEARNING (asynchronous)
learning record (failure/victory) → vector re-indexing →
human-validated suggestion → persisted memory rule →
reflex available in next session
On the outbound email side, nothing ever reaches an external recipient directly: everything goes through the email-sending facade (draft → validation copy for the operator → send after explicit approval). The system writes to the internal operator, never to the requester.
Scheduling relies on the Linux crontab: IMAP poll and scan continuously (*/1 min), spawn with offset (*/5 min + 120 s), task worker continuously (*/1 min), plus 69 active cron entries for recurring automation, workers, and watchers.
4. Cardinal terms glossary
| Name | Definition | Physical backing |
|---|---|---|
| Orchestrator (Atlas) | The harness conductor. A persona registered in the database with no dedicated runtime: "being the orchestrator" = launching an LLM engine with the dedicated system prompt. Drives classification, spawn, and post-spawn orchestration. | Orchestration Python facades + pseudo-TTY spawn module |
| Agent | A persona (identity + cognitive frame + business scope) injected into an LLM engine context to execute a task. 30 active agents across 4 families: direction, cadrage, execution, validation. An agent deliberates (ReAct cycle); it does not execute a hard-coded routine. |
Agent registry in the database; persona loaded by a dedicated facade; 30 definitions in the agent directory |
| Automate | A deterministic script that executes a routine; may call an LLM but its control flow is hard-coded. The conceptual opposite of an agent. | Automation registry in the database; dedicated execution log |
| Chantier | A structured multi-step mission. The highest-level unit of work. Created atomically with ≥1 work package and ≥1 task via a dedicated procedure. Hierarchy: 1 chantier = N work packages = N tasks. | Mission table in the database |
| Travail | A granular batch within a chantier (phase or sub-objective), with its responsible agent, scope, and exit criteria. Carries status cascades and the unblocking mechanism (travail-bis). |
Work packages table in the database |
| Tâche | The atomic unit assigned to an agent, with a token estimate and recommended model. | Tasks table in the database |
| Run | A scoped execution driven by the orchestrator on a perimeter (internal cockpit or client site), the perimeter loading its context (server, client, mailbox). Trigger: forwarded email or control console. A task execution record is NOT a run: it is the execution unit delegated to an agent. | Runs table in the database; dedicated control console |
| Cicatrice | A recorded lesson from a failure (kind='failure') or a reproducible success (kind='victory'). Indexed as vectors for semantic recall, scored by importance, the entry point of the learning loop. |
Learning records table in the database + pgvector index |
| Orbit | Organizational ring for agents (1/2/3). A dual concept: the numeric database column (underused) does not map 1:1 to the visual reactor display, which recomputes the ring from the family (direction=1, cadrage/execution=2, validation=3). The family field is authoritative. |
orbite column + group_name column in the agent registry |
| Facade | A single mandatory entry point for a capability, making an operation non-bypassable (email, AI invocation, antivirus scan, database access). Often paired with a hook that blocks bypass attempts. | Python facades + pre-tool verification hooks |
Other useful terms: knock-gate (nginx cookie+slug filter upstream of the cockpit), pseudo-TTY (virtual terminal required to spawn the LLM engine programmatically), scan-first (doctrine: no attachment opened before an antivirus clean verdict), travail-bis (work package carrying an unblocking reference to release a paused work package).
5. Hard boundaries (non-negotiable)
A condensed reminder of the rules the entire harness enforces:
- Single database — zero business content in static files (JSON, TypeScript, Markdown); everything in the database.
- Secret anti-leak P0 — no secret in cleartext in any versioned file; secrets live in environment files outside the repository, referenced only by variable name.
- Antivirus scan before opening — any attachment remains closed until the antivirus engine returns a
cleanverdict. - Zero direct client communication by the system — email-sending facade + human validation before send + appointments exclusively via the canonical scheduling link.
- 7-step procedure — no chantier without atomic creation via the dedicated procedure, with ≥2 distinct agents for a client-scoped perimeter.
- Commit-in-flow — no completed work without an immediate commit; the AI commits, the human operator never types low-level git commands; a blocking hook enforces the invariant at every session end.
6. Other documentation pages
| Page | Subsystem covered |
|---|---|
| 02 — The data layer | Single database, table prefixes, MySQL→PostgreSQL adapter, Python Entity classes, legacy shim views, i18n in the database |
| 03 — The agentic core | Orchestrator, agent model, intent classification, pseudo-TTY spawn, deploy→QA→email orchestration, orbits, calibration |
| 04 — Chantiers, work packages and tasks | Mission/work/task hierarchy, atomic creation, 7-step procedure, multi-session lock, status cascades, travail-bis |
| 05 — Automations, crons and runs | 236 facades, cron wrapper, automation registry, run vs. task execution record, dual scheduler (Nitro offline + crontab) |
| 06 — The cockpit | Nuxt application, modules, control pages, internal endpoints, knock-gate + auto-session authentication, consoles |
| 07 — Inbox, agentic mailbox and email | Two IMAP pipelines (cockpit vs. agentic mailbox), email-sending facade, antivirus scan, zero direct communication |
| 08 — Memory and learning | 3-level memory (persistent files / notes / vector index), RAG recall, cicatrices→suggestions→lessons loop, unified AI facade |
| 09 — Deployment and infrastructure | Deploy/publish asymmetry, YAML dispatcher, build + compressed transfer, cockpit self-deploy, server inventory, secrets, commit-before-deploy |
| 10 — Facade and entrypoint catalogue | Python facades + scripts by family, invocation mode (cron/CLI/skill/hook/lib), hooks catalogue |
| 11 — Skills, agents and hooks | Slash-command skills, sub-agent definitions, configuration hooks + permissions/env |