Engelbot¶
The Middleware. The Referee. The Midfielder.¶
You type a command. The ledger updates. The audit trail grows.
Engelbot is what happens in between.
What is Engelbot?¶
Engelbot is a Matrix bot — a Node.js/TypeScript process that lives inside the Element workspace, listens to every message, and acts as the enforcer of constitutional rules at the point of human interaction.
It has one job: make sure that no owner ever touches a CSV directly.
The ADM Pattern — Midfielder Role
At every level of SmartupOS, work is structured as a triangle: an Attacker who executes, a Defender who oversees, and a Midfielder who coordinates. Engelbot is the permanent Midfielder for the entire organisation. It coordinates between humans and the ledger — never deciding, always routing.
Every !command typed in Matrix passes through Engelbot before anything is written.
It validates identity, checks permissions, runs the constitutional script, and reports the outcome — all without the owner ever seeing a file path, a SHA, or a CSV row.
Engelbot in the Stack¶
flowchart TD
H["👤 Owner\n(Matrix / Element)"]
E["🤖 Engelbot\n(Node.js / TypeScript)"]
T["🔧 Toolbox API\n(Flask / Python)"]
S["📜 Toolbox Scripts\n(Python — constitutional enforcement)"]
F[("📦 Forgejo\nCSV Ledgers + Wiki")]
H -->|"!command (plain text)"| E
E -->|"Permission pre-check\n(reads CSV directly)"| E
E -->|"HTTP POST /api/endpoint"| T
T -->|"python3 script.py --json"| S
S -->|"SHA-locked write"| F
F -->|"Confirmed"| S
S -->|"JSON result"| T
T -->|"HTTP response"| E
E -->|"Human-readable reply"| H
Engelbot performs a lightweight permission check before calling the API —
reading the book-of-owners.csv directly from Forgejo to fail fast without
a round-trip to the Toolbox. If the actor lacks the required role, they get
a clear error message before any script runs.
Reads Direct, Writes via API
Engelbot reads CSV data directly from Forgejo (fast, no Python overhead). It never writes directly. All mutations go through the Toolbox API → Python scripts → constitutional enforcement → SHA-locked Forgejo commit.
The Command System¶
Engelbot responds to !commands typed in any authorised Matrix room.
Commands are grouped by permission level.
Available to all owners regardless of role.
| Command | Aliases | What it does |
|---|---|---|
!whoami |
— | Show your identity, roles, and status |
!wallet |
!my_sc |
Your SC balance and SK score |
!show |
!lookup |
Resolve any SmartupOS ID (5_1_3, 6_2_4_1, etc.) |
!my_tasks |
!mytasks |
List your open and assigned tasks |
!my_apps |
!my_applications |
View your open role applications |
!open_roles |
— | Browse available roles (optional team filter) |
!help |
— | Full command list |
!cancel |
— | Cancel any active conversation |
Available to anyone with an assigned role (4_0_X, 4_1_X, 4_2_X, 4_3_X).
| Command | What it does |
|---|---|
!claim_task |
Express interest in a task (captain must approve) |
!start_work |
Clock in — begins a paired Attacker + Defender session |
!stop_work |
Clock out — triggers session log + moves task to review |
!apply_for_role / !apply |
Submit an application for an open role |
!ratify / !confirm_ownership |
Complete identity binding during onboarding |
Available to 4_1_X (team captains) and 4_1_1 (founder).
| Command | What it does |
|---|---|
!create_task |
Open a new task under an objective |
!create_objective |
Define a new team or global objective |
!update_task |
Edit task metadata, status, or budget |
!update_objective |
Progress, cancel, or complete an objective |
!assign_task |
Assign attacker + defender to a claimed task |
!assess_work |
Score a completed session → triggers SC payout |
!define_role |
Create a new role with wiki + CSV entry |
!update_role |
Modify an existing role definition |
!review_app / !review_application |
Approve or reject a role application |
!award_sk |
Directly award Social Karma to a contributor |
!sync_progress |
Sync ledger state to Forgejo issue boards |
!update_portfolio |
Regenerate an owner's portfolio markdown |
!new_wiki_page |
Create a free-form wiki page in the ledger |
Multi-Step Conversations¶
Most write commands are not single-shot. They open a guided conversation — a wizard that collects structured input step by step before committing anything to the ledger.
sequenceDiagram
participant O as Owner
participant E as Engelbot
participant T as Toolbox API
O->>E: !create_task
E->>O: "Which objective? (e.g. 5_3_0)"
O->>E: 5_3_0
E->>O: "Task title?"
O->>E: Write the onboarding guide
E->>O: "Budget tier? (1=10SC 2=50SC 3=100SC 4=200SC)"
O->>E: 2
E->>T: POST /api/create_task {actor, objective_id, title, budget...}
T->>E: {status: "ok", task_id: "6_5_3_1", ...}
E->>O: ✅ Task 6_5_3_1 created — 50 SC budget
While a conversation is active, every message from that user is routed to the
continuation handler — not the command router. Type !cancel at any point to abort
without side effects.
One Conversation at a Time
Each owner can have only one active conversation. Starting !create_task while
!assign_task is open will not work — Engelbot will remind you to !cancel first.
Technical: How Conversation State Works
Each multi-step handler stores state in a Map<userId, ConversationState>:
interface ConversationState {
command: "create_task"; // literal type — one per command
step: number; // drives the switch in continueXxx()
userId: string;
roomId: string;
data: { // accumulates through steps
objective_id?: string;
title?: string;
budget_tier?: number;
};
}
matrixClient.ts checks isInXxxConversation(userId) before the !command router.
If a conversation is active, the message goes to continueXxx(). Otherwise it hits the
command switch. This ordering is intentional — it prevents a mid-conversation message
that happens to start with ! from triggering a different command.
The Permission Model¶
Engelbot enforces permissions at two levels — a fast pre-check in TypeScript, and a deep constitutional check inside the Python script.
flowchart LR
MSG["!command"] --> PC["TS Pre-check\nRead book-of-owners.csv\nCheck role_assignments"]
PC -->|"Fail"| ERR1["❌ Insufficient permissions\n(no API call made)"]
PC -->|"Pass"| API["POST /api/endpoint"]
API --> PY["Python script\nFull permission check\n+ business logic"]
PY -->|"Fail"| ERR2["❌ Error message\n(no ledger write)"]
PY -->|"Pass"| WRITE["SHA-locked\nledger write"]
Role codes follow the pattern 4_[seniority]_[team]:
| Code | Role | Permissions |
|---|---|---|
4_1_1 |
Founder | All permissions |
4_1_X |
Team Captain | All teamcaptain scripts for their team |
4_2_X |
Senior (Attacker) | Worker scripts |
4_3_X |
Junior (Defender) | Worker scripts |
SK-Gated Actions
Some actions require a minimum Social Karma threshold — not a role code. 50 SK to propose votes · 100 SK to run for captain · 200 SK for mission leader. These thresholds are enforced in the Python scripts, not the TS pre-check.
Named After a Giant¶
Engelbot is named after Douglas Engelbart — the computer scientist who, in 1968, demonstrated the mouse, hypertext, and collaborative real-time editing in a single 90-minute presentation now known as The Mother of All Demos.
Engelbart's life work was Collective IQ: the hypothesis that well-designed tools could amplify the intelligence and capability of human groups — not just individuals.
Smartup Zero tests exactly that hypothesis. Engelbot is the tool through which collective decisions are made, recorded, and made permanent.
Douglas Engelbart, 1962
"The key question is not whether we can augment the individual's intellect, but whether we can augment the collective intellect of a group working on a problem together."
Source & Hosting¶
Engelbot lives in the 3_7_operational_team private repository on Forgejo.
It runs as a persistent Node.js process on EU-sovereign infrastructure,
authenticated to the Matrix homeserver at smartup0.org with a dedicated bot account.
Technical: Key Source Files
| File | Purpose |
|---|---|
src/matrixClient.ts |
Main event loop + command router |
src/commands/handleXxx.ts |
One file per command — start, continue, check, cancel |
src/forgejo_client.ts |
Direct Forgejo reads (CSV + markdown) |
src/services/toolboxClient.ts |
HTTP client for Toolbox API writes |
The router in matrixClient.ts is the ground truth for what Engelbot responds to.
When in doubt, check the switch statement in handleCommand().