docs: codify the SecuBox CTL grammar (closes #216) (#217)

Permanent documentation for the 8-verb / 8-layer modular tools box that
emerged across #173, #176, #180-#184, #190, #212. Three new docs + one
README section, all bearing the 1991 attribution.

  docs/grammar.md            Canonical conceptual frame: layered map,
                             8 verbs in a table, composing-the-grammar
                             worked examples, naming conventions,
                             philosophical roots.

  HOWTO-grammar.md           Concrete 6-step walkthrough for adding a
                             9th verb (~1h budget): issue framing,
                             worktree, CTL skeleton (Bash + Python),
                             FastAPI mirror, Debian packaging, nginx
                             route under secubox-routes.d/, live test
                             on the board, commit/PR conventions,
                             common pitfalls drawn from real incidents
                             (#163 secubox.d vs secubox-routes.d,
                             #173 LXC default path, #176 hook trigger,
                             #194 CAP_NET_ADMIN, #180 naming).

  wiki/CTL-Grammar.md        Public-facing wiki page mirrored to the
                             GitHub wiki repo (per the wiki-sync
                             pattern established for Acknowledgments).
                             Embeds Punk Exposure (Peek/Poke/Emancipate)
                             as the seed concept with 1991 attribution.

  README.md                  New section under Features summarising the
                             grammar with the 9-row layer table and a
                             pointer to docs/grammar.md + HOWTO-grammar.md.

Attribution recorded on all three documents: copyright spiritual
concept Gerald Kerma (GK2), 1991, Notre-Dame-du-Cruet, Savoie.

The CTL is the user's voice. The modular tools box is their organ. The
language is the way they say *this is mine, this is mine, this is mine*.

Co-authored-by: CyberMind-FR <gandalf@Gk2.net>
This commit is contained in:
CyberMind 2026-05-19 08:01:08 +02:00 committed by GitHub
parent b5c8262c17
commit 53a630e9f8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 689 additions and 0 deletions

326
HOWTO-grammar.md Normal file
View File

@ -0,0 +1,326 @@
# HOWTO — forge a new CTL verb
> *Copyright spiritual concept · Gérald Kerma · 1991*
>
> This is the concrete walkthrough. See `docs/grammar.md` for the
> conceptual frame and the 8 canonical verbs already in place.
You want to add `xctl widget add/remove/list` (or any 9th verb). Follow
these steps in order. Time budget: ~1 hour for a Bash-style verb,
~2 hours for a Python+FastAPI one.
---
## 1. Frame the gap
Write the issue body following this template (adapt verbs/nouns):
```markdown
## Context
The X module already exposes <capability> via the web UI and FastAPI, but
operators have no CLI grammar for it. Closing the gap parallel to:
- `mitmproxyctl route add` (#173) — INTERCEPTION
- `giteactl repo mirror add` (#176) — REPLICATION
## Gap
Forge `xctl widget` with subcommands:
xctl widget add NAME [--option ...]
xctl widget remove NAME
xctl widget list
xctl widget status NAME
## Out of scope
(Anything you defer to a followup ticket.)
```
Submit, capture the issue number. Reference it as `#<N>` in everything
that follows.
---
## 2. Worktree
```bash
scripts/agent-worktree.sh start --issue <N>
cd ~/CyberMindStudio/secubox-deb-worktrees/<N>-<slug>
```
You're now on a branch named `feature/<N>-<slug>` (or `fix/...` if the
issue is labeled `bug`). Every commit message ends with `(ref #<N>)` or
`(closes #<N>)` on the final commit.
---
## 3. Pick the language
| When | Use |
|---|---|
| The verb is mostly shell-orchestration (lxc-attach, systemctl, file ops) | Bash |
| The verb needs rich subparsers, JSON I/O, or a registry pattern | Python |
Both styles exist in-tree. Reference implementations:
- **Bash**`packages/secubox-gitea/sbin/giteactl`, `packages/secubox-metablogizer/sbin/metablogizerctl`
- **Python**`packages/secubox-mitmproxy/bin/mitmproxyctl`, `packages/secubox-health-doctor/sbin/healthctl`
---
## 4. Skeleton
### Bash skeleton
```bash
#!/bin/bash
# SPDX-License-Identifier: LicenseRef-CMSD-1.0
# Copyright (c) 2026 CyberMind — Gérald Kerma <devel@cybermind.fr>
#
# xctl — SecuBox X control (issue #<N>).
set -euo pipefail
VERSION="0.1.0"
CONFIG_FILE="/etc/secubox/x.toml"
GREEN='\033[0;32m'; YELLOW='\033[1;33m'; RED='\033[0;31m'; NC='\033[0m'
log() { printf "${GREEN}[X]${NC} %s\n" "$*"; }
warn() { printf "${YELLOW}[WARN]${NC} %s\n" "$*"; }
error() { printf "${RED}[ERROR]${NC} %s\n" "$*" >&2; }
# Lifecycle
cmd_start() { systemctl start secubox-x.service && log started; }
cmd_stop() { systemctl stop secubox-x.service && log stopped; }
cmd_restart() { systemctl restart secubox-x.service && log restarted; }
cmd_status() { systemctl is-active secubox-x.service; }
cmd_logs() { journalctl -u secubox-x.service -n "${1:-50}" --no-pager; }
# Three-fold (JSON discovery)
cmd_components() {
cat <<EOF
{"service":"secubox-x.service","api_base":"/api/v1/x","ctl_version":"$VERSION"}
EOF
}
cmd_access() {
cat <<EOF
{"api":{"list":"GET /widgets","add":"POST /widget","remove":"DELETE /widget/{name}"}}
EOF
}
# Widget noun
cmd_widget() {
local act="${1:-}"; shift || true
case "$act" in
add) widget_add "$@" ;;
remove|rm|delete) widget_remove "$@" ;;
list|ls) widget_list "$@" ;;
status) widget_status "$@" ;;
*) echo "Usage: xctl widget {add|remove|list|status} [args]" ;;
esac
}
widget_add() { :; } # implement: name validation, side effect, idempotent
widget_remove() { :; }
widget_list() { :; }
widget_status() { :; }
case "${1:-}" in
start|stop|restart|status) c="$1"; shift; cmd_$c "$@" ;;
logs) shift; cmd_logs "$@" ;;
components) cmd_components ;;
access) cmd_access ;;
widget) shift; cmd_widget "$@" ;;
*) echo "Usage: xctl <command>"; exit 1 ;;
esac
```
### Python skeleton
```python
#!/usr/bin/env python3
# SPDX-License-Identifier: LicenseRef-CMSD-1.0
# Copyright (c) 2026 CyberMind — Gérald Kerma <devel@cybermind.fr>
"""xctl — SecuBox X control (#<N>)."""
from __future__ import annotations
import argparse, json, sys
from pathlib import Path
sys.path.insert(0, "/usr/lib/secubox/x")
from api import engine # canonical writer used by FastAPI too
def cmd_widget_add(args): engine.widget_add(args.name); return 0
def cmd_widget_remove(args): engine.widget_remove(args.name); return 0
def cmd_widget_list(args): print(json.dumps(engine.widget_list(), indent=2)); return 0
def build_parser():
p = argparse.ArgumentParser(prog="xctl")
sub = p.add_subparsers(dest="cmd", required=True)
for n in ("start", "stop", "restart", "status", "components", "access", "logs"):
sub.add_parser(n)
w = sub.add_parser("widget"); ws = w.add_subparsers(dest="wc", required=True)
add = ws.add_parser("add"); add.add_argument("name"); add.set_defaults(func=cmd_widget_add)
rm = ws.add_parser("remove"); rm.add_argument("name"); rm.set_defaults(func=cmd_widget_remove)
ls = ws.add_parser("list"); ls.set_defaults(func=cmd_widget_list)
return p
def main():
args = build_parser().parse_args()
return args.func(args) if hasattr(args, "func") else 0
if __name__ == "__main__":
sys.exit(main())
```
---
## 5. FastAPI mirror
Every verb has a route. Same engine, two callers (CTL and API).
```python
# packages/secubox-x/api/main.py
from fastapi import FastAPI
from . import engine
app = FastAPI(root_path="/api/v1/x")
@app.get("/widgets")
def widget_list(): return engine.widget_list()
@app.post("/widget")
def widget_add(name: str): return engine.widget_add(name)
@app.delete("/widget/{name}")
def widget_remove(name: str): return engine.widget_remove(name)
```
The CTL and the web UI both call into `engine.widget_*`. **Don't
duplicate business logic** between CTL and API — they're two surfaces
on the same engine.
---
## 6. Debian packaging
`packages/secubox-x/debian/`:
- `control` — Depends on `secubox-core`, `python3-uvicorn`, etc.
- `changelog` — bump version, include `Closes: #<N>`.
- `rules` — install the CTL to `/usr/sbin/xctl`, the API to
`/usr/lib/secubox/x/`, the systemd unit to `/lib/systemd/system/`.
- `postinst``systemctl enable --now secubox-x.service` (idempotent).
- `prerm``systemctl disable --now secubox-x.service`.
systemd unit boilerplate:
```ini
[Unit]
Description=SecuBox X
After=network.target secubox-core.service
[Service]
Type=simple
User=secubox
Group=secubox
WorkingDirectory=/usr/lib/secubox/x
ExecStart=/usr/bin/python3 -m uvicorn api.main:app \
--uds /run/secubox/x.sock --log-level warning
Restart=on-failure
ReadWritePaths=/run/secubox /var/cache/secubox
[Install]
WantedBy=multi-user.target
```
If your CTL needs to read nft sets, add
`AmbientCapabilities=CAP_NET_ADMIN` (see #194 — without it,
`subprocess.run(["nft", ...])` silently returns empty).
---
## 7. Nginx route (so the API is reachable via admin.gk2)
Add `/etc/nginx/secubox-routes.d/x.conf`:
```nginx
location /api/v1/x/ {
proxy_pass http://unix:/run/secubox/x.sock:/api/v1/x/;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_read_timeout 60s;
}
```
This goes in `secubox-routes.d/`, **not** `secubox.d/` — the admin.gk2
server block includes the former (lesson learned from #163).
---
## 8. Live test on the board
The verb is only forged when it survives prod. From your worktree:
```bash
# Copy the CTL onto the board first
scp packages/secubox-x/sbin/xctl root@192.168.1.200:/usr/sbin/
ssh root@192.168.1.200 'xctl access | jq .' # discovery
ssh root@192.168.1.200 'xctl widget add demo' # the new verb
ssh root@192.168.1.200 'xctl widget list' # observe side-effect
```
If anything is wrong, the operator's CLI tells them so. That's the
whole point of the grammar.
---
## 9. Commit + PR
Commit messages stay terse. Don't include AI attribution footers — the
project's global reference is enough. Example:
```text
feat(xctl): forge widget noun verbs (closes #<N>)
Ninth verb of the SecuBox grammar, layer = <layer>. Parallel to
mitmproxyctl route (#173), giteactl repo mirror (#176).
Subcommands:
xctl widget add NAME [--option ...]
xctl widget remove NAME
xctl widget list
xctl widget status NAME
Live-tested on gk2 board: <one-line observation>.
```
Push the branch, open the PR with a one-paragraph summary + a test plan
checklist. Don't add `🤖 Generated with Claude Code` style footers.
---
## 10. Update grammar.md
After merge, add a row to the canonical table in `docs/grammar.md` and
the wiki version. The grammar is a living document; new verbs extend it.
---
## Common pitfalls
- **Naming**: it's `<module>ctl`, not `<module>-ctl` or `<module>_ctl`.
Renaming after the fact (e.g. `metactl``publishctl` in #180) is
user-hostile; pick right from the start.
- **Nounlessness**: don't ship a flat verb set without a noun. `xctl
upload` invites future verb collisions; `xctl widget upload` does not.
- **AmbientCapabilities** vs `NoNewPrivileges`: they coexist when caps
are set in the unit (#194).
- **Filesystem fetches don't trigger Gitea hooks** (#176): for verbs
that pull data into Gitea-managed repos, use Gitea's API, not
`git fetch` on the bare repo from the host.
- **Default LXC paths**: board reality is `/data/lxc/`, not
`/var/lib/lxc/` (#173). Auto-detect or read from config.
- **The grammar surfaces real bugs**: when `healthctl check` flags 4/11
failing on first run, those are real anomalies, not check bugs.

View File

@ -168,6 +168,38 @@ Automatic threat detection and IP blocking with community threat intelligence.
---
## CTL Grammar — modular tools box
> *Copyright spiritual concept · Gérald Kerma · 1991*
Each SecuBox module exposes its capability through three surfaces — a
web UI, a FastAPI API, and a CTL command (`/usr/sbin/<module>ctl`). The
CTL is the **grammar** of the system: each verb is a sentence addressed
to a specific layer of the operator's expressive control over their own
infrastructure.
| Layer | Verb |
|----------------------|---------------------------------------------------|
| ROUTING | `haproxyctl vhost add/remove` |
| INTERCEPTION | `mitmproxyctl route add/remove/list` |
| REPLICATION | `giteactl repo mirror add/remove` |
| IDENTITY | `giteactl user add/remove` |
| CI EXECUTION | `giteactl runner add/remove/list` |
| PUBLISHING | `publishctl post` / `dropletctl publish` / `metablogizerctl site` |
| EMANCIPATE | `metablogizerctl tor expose/revoke` |
| HOSTING | `streamlitctl app deploy/.../info` |
| DEV WORKBENCH | `streamforgectl project create/.../templates` |
| OPS MONITORING | `healthctl check/list/status/alert` |
Composing the verbs expresses end-to-end workflows in three lines of
shell. See [`docs/grammar.md`](docs/grammar.md) for the conceptual
frame and the layered architecture map.
To **add a 9th verb**, follow [`HOWTO-grammar.md`](HOWTO-grammar.md) —
the six-step recipe takes about an hour for a Bash CTL.
---
## Eye Remote — External Dashboard
<p align="center">

213
docs/grammar.md Normal file
View File

@ -0,0 +1,213 @@
# SecuBox CTL Grammar
> *Copyright spiritual concept · Gérald Kerma · 1991 ·
> Notre-Dame-du-Cruet, Savoie · https://cybermind.fr*
>
> SecuBox is a **modular tools box** — a security-affected modular language
> system that acts as an interface between users and the world of data
> publishing of each user around the connected humanities. The 1991 concept
> matured through SecuBox-OpenWrt and incarnates here as SecuBox-Deb on
> Debian bookworm arm64/amd64. This document codifies the CLI grammar that
> makes the modular concept expressible from the shell.
---
## The frame
Each SecuBox module exposes its capability through three surfaces:
1. **A web UI** (under `/<module>/` on the admin vhost)
2. **A FastAPI API** (`/api/v1/<module>/*` over a Unix socket)
3. **A CTL command** (`/usr/sbin/<module>ctl`)
The CTL is the **grammar** of the system: each verb is a sentence in the
modular language, addressed to a specific layer of the operator's
expressive control over their own infrastructure.
Without the CTL the organ exists but cannot be commanded —
**instrumentation without préhension**. The CTL gives the operator
*préhension* (grasping power) over what the module already instruments.
---
## The 8 layers / 8 canonical verbs
| Layer | Verb | Forged in |
|----------------------|---------------------------------------------------|-----------|
| ROUTING | `haproxyctl vhost add/remove` | pre-2026 |
| INTERCEPTION | `mitmproxyctl route add/remove/list` | #173 |
| REPLICATION | `giteactl repo mirror add/remove/sync/list` | #176 |
| IDENTITY | `giteactl user add/remove/passwd/list` | pre-2026 |
| CI EXECUTION | `giteactl runner add/remove/list/token` | #190 |
| PUBLISHING (bundle) | `publishctl post upload/publish/...` | #180 |
| PUBLISHING (file) | `dropletctl publish/list/remove/rename` | #181, #196 |
| PUBLISHING (static) | `metablogizerctl site create/publish/...` | pre-2026 |
| EMANCIPATE | `metablogizerctl tor expose/revoke/list/status` | #184 |
| HOSTING | `streamlitctl app deploy/start/.../info/restart` | #182 |
| DEV WORKBENCH | `streamforgectl project create/.../templates` | #183 |
| OPS MONITORING | `healthctl check/list/status/alert` | #212 |
Each verb closes a previously implicit operation. Composing them
expresses end-to-end workflows in three lines of shell:
```bash
# WAF un-bypass for a vhost (the cookie-audit cascade fix, today's grammar):
haproxyctl vhost add gitea.gk2.secubox.in mitmproxy_inspector ssl
mitmproxyctl route add gitea.gk2.secubox.in 192.168.1.200 9080
giteactl repo mirror add secubox/secubox-deb \
https://github.com/CyberMind-FR/secubox-deb.git \
--interval 10m --force
```
```bash
# Forge → host → expose pipeline (apps + static):
streamforgectl project create dashboard --template basic
streamlitctl app deploy dashboard gitea://secubox/dashboard.git
metablogizerctl site publish dashboard
metablogizerctl tor expose dashboard # Punk Exposure
```
```bash
# Daily ops dance:
healthctl check # 60s pulse on vital services
healthctl alert --since 1h # what failed or recovered
```
---
## Pattern recipe — adding the 9th verb
A new `<module>ctl <noun> <verb>` follows the same six-step recipe every
time:
### 1. Open an issue framing the gap
State the **layer**, the **noun**, and the **operator workflow** that
currently has no expressible form. Quote any sibling-grammar tickets (e.g.
"parallel to #173 on the interception layer"). The issue is the design
document; subsequent PRs reference it.
### 2. Worktree per issue
```bash
scripts/agent-worktree.sh start --issue <N>
```
This enforces the multi-agent worktree workflow (`.claude/CLAUDE.md`):
the primary checkout stays on master, every non-trivial feature lives in
its own worktree, each commit references `(ref #N)` or `(closes #N)`.
### 3. CTL skeleton
Bash for shell-shaped tools (giteactl, metablogizerctl), Python with
`argparse` for tools with rich subcommands and JSON I/O (mitmproxyctl,
healthctl). Both styles co-exist; pick the one closest to the existing
ctls in the same package.
Three subsections in every CTL:
```text
Lifecycle (top-level) install start stop restart status logs
Three-fold (JSON) components access
<noun> <verb>(s) the new grammar
```
The Three-fold pair (`components` and `access`) is the discovery contract
— operators run `<x>ctl access` to learn what the module exposes without
reading source. See `giteactl` and `healthctl` for the canonical shape.
### 4. FastAPI mirror
Every verb is a function. Every function gets a route under
`/api/v1/<module>/*`. The CTL becomes a thin wrapper over the API when
running on the box, and the same routes are consumed by the web UI from
the browser. CTL ↔ API parity is mechanical (one engine, two call sites).
See `packages/secubox-users/api/engine.py``sbin/usersctl` for the
reference pattern.
### 5. systemd integration
If the verb daemonizes anything, ship the unit:
```text
debian/<service>.service Type=simple, User=secubox, ExecStart=python3 -m uvicorn ...
debian/<service>-runner.timer for periodic actions (health-doctor, geoipupdate)
```
The Debian `postinst` enables units; the `prerm` disables them. Both are
idempotent. Use `AmbientCapabilities=` rather than running as root — we
discovered (#194) that missing CAP_NET_ADMIN silently breaks aggregators
that need to read `nft` sets.
### 6. Live test on the prod board
The grammar is empirical — a verb is only forged when it survives a live
deploy on `gk2` (192.168.1.200). The PR body documents the verification:
the exact command, the observable side-effect, the API endpoint check.
---
## Naming conventions
- `<module>ctl` (single binary name, no separator). `metactl` was renamed
`publishctl` in #180 to align.
- Verbs are imperative present tense: `add` / `remove` / `list` / `status`,
not `creating` / `deletion` / `listed`.
- Nouns are singular: `route`, `repo`, `app`, `project`, `vhost`, `user`.
- Aliases are accepted but not advertised in `--help`: `rm`/`del` for
`remove`, `ls` for `list`.
- Three-fold output is always JSON (machine-readable). Other commands
human-friendly by default; `--json` flag opt-in.
---
## Layered architecture map
```text
┌─────────────────────────────────────────────────────────────────────┐
│ EMANCIPATE metablogizerctl tor (#184) Punk Exposure │
├─────────────────────────────────────────────────────────────────────┤
│ PUBLISHING metablogizerctl site, publishctl post (#180), │
│ dropletctl publish (#181/#196) │
│ HOSTING streamlitctl app (#182), streamforgectl project (#183)│
├─────────────────────────────────────────────────────────────────────┤
│ IDENTITY giteactl user │
│ REPLICATION giteactl repo mirror (#176) │
│ CI EXECUTION giteactl runner (#190) │
├─────────────────────────────────────────────────────────────────────┤
│ INTERCEPTION mitmproxyctl route (#173) │
│ ROUTING haproxyctl vhost │
├─────────────────────────────────────────────────────────────────────┤
│ OPS MONITORING healthctl (#212) │
│ surveille les 9 couches ci-dessus │
└─────────────────────────────────────────────────────────────────────┘
```
The monitoring layer at the bottom is meta — `healthctl` watches the
state of the other nine and surfaces transitions via journal events.
---
## Philosophical roots
The SecuBox concept was conceived by **Gérald Kerma (GK²)** in **1991**
as a modular tools box for user-controlled digital sovereignty over
personal data publishing. The Punk Exposure verbs (`Peek`/`Poke`/
`Emancipate`) trace back to that origin: three modes of expression
through which the user occupies their own infrastructure rather than
delegate it. The 8-verb CLI grammar is the operational incarnation of
that frame on Debian, 35 years later.
The CTL is the user's voice. The modular tools box is their organ. The
language is the way they say *this is mine, this is mine, this is mine*.
---
## See also
- `HOWTO-grammar.md` — concrete walkthrough for adding a 9th verb
- `wiki/CTL-Grammar.md` — public-facing summary on the GitHub wiki
- `.claude/CLAUDE.md` — operational rules for agents (worktree workflow,
per-package conventions, hard rules)
- Issues #173, #176, #180-#184, #190, #212 — the forging history

118
wiki/CTL-Grammar.md Normal file
View File

@ -0,0 +1,118 @@
# SecuBox CTL Grammar
> *Copyright spiritual concept · Gérald Kerma · 1991 ·
> Notre-Dame-du-Cruet, Savoie · https://cybermind.fr*
>
> SecuBox is a **modular tools box** — a security-affected modular
> language system that acts as an interface between users and the world
> of data publishing of each user around the connected humanities. The
> 1991 concept matured through SecuBox-OpenWrt and now incarnates as
> SecuBox-Deb on Debian bookworm.
## The frame
Each SecuBox module exposes its capability through three surfaces:
1. A **web UI** under `/<module>/` on the admin vhost
2. A **FastAPI API** at `/api/v1/<module>/*` over a Unix socket
3. A **CTL command** at `/usr/sbin/<module>ctl`
The CTL is the **grammar** of the system: each verb is a sentence
addressed to a specific layer of the operator's expressive control over
their own infrastructure. Without the CTL the organ exists but cannot
be commanded — instrumentation without préhension.
## The 8 layers / 8 canonical verbs
| Layer | Verb |
|----------------------|---------------------------------------------------|
| ROUTING | `haproxyctl vhost add/remove` |
| INTERCEPTION | `mitmproxyctl route add/remove/list` |
| REPLICATION | `giteactl repo mirror add/remove/sync` |
| IDENTITY | `giteactl user add/remove/passwd` |
| CI EXECUTION | `giteactl runner add/remove/list` |
| PUBLISHING (bundle) | `publishctl post upload/publish/list` |
| PUBLISHING (file) | `dropletctl publish/list/remove/rename` |
| PUBLISHING (static) | `metablogizerctl site create/publish/...` |
| EMANCIPATE | `metablogizerctl tor expose/revoke/list` |
| HOSTING | `streamlitctl app deploy/start/.../info` |
| DEV WORKBENCH | `streamforgectl project create/.../templates` |
| OPS MONITORING | `healthctl check/list/status/alert` |
## Composing the grammar
```bash
# WAF un-bypass for a vhost (three layers, three verbs, one operation):
haproxyctl vhost add gitea.gk2.secubox.in mitmproxy_inspector ssl
mitmproxyctl route add gitea.gk2.secubox.in 192.168.1.200 9080
giteactl repo mirror add secubox/secubox-deb \
https://github.com/CyberMind-FR/secubox-deb.git \
--interval 10m --force
```
```bash
# Forge → host → expose pipeline:
streamforgectl project create dashboard --template basic
streamlitctl app deploy dashboard gitea://secubox/dashboard.git
metablogizerctl site publish dashboard
metablogizerctl tor expose dashboard # Punk Exposure / Emancipate
```
```bash
# Daily ops:
healthctl check # 60s pulse on vital services
healthctl alert --since 1h
```
## Three-fold pair on every CTL
Every CTL ships two JSON discovery subcommands:
- `<x>ctl components` — what processes/sockets/configs back this module
- `<x>ctl access` — the API endpoints + CLI subcommands exposed
Operators learn the grammar by running `<x>ctl access | jq .`.
## Punk Exposure roots
The three-verb Punk Exposure pattern (`Peek` / `Poke` / `Emancipate`)
predates the CLI grammar — it is the **conceptual seed** that the
modular tools box is built around:
- **Peek** — read state without mutation (the discovery surface)
- **Poke** — local mutation under operator control
- **Emancipate** — multi-channel exposure (Tor / DNS+SSL / Mesh) that
takes the user's data and publishes it on the user's terms
`metablogizerctl tor expose` is the canonical Emancipate verb at the
publishing layer (issue #184).
## Want to add a 9th verb?
See `HOWTO-grammar.md` in the repo for the concrete walkthrough (~1h for
a Bash CTL, ~2h for Python+FastAPI). The recipe is six steps: frame the
gap as an issue, worktree, CTL skeleton, FastAPI mirror, Debian
packaging, live test on the board.
## Attribution
The SecuBox concept was conceived by **Gérald Kerma (GK²)** in **1991**
as a modular tools box for user-controlled digital sovereignty over
personal data publishing. The Punk Exposure verbs (Peek / Poke /
Emancipate) trace back to that origin. The 8-verb CLI grammar
incarnates the same frame on Debian, 35 years later.
> The CTL is the user's voice.
> The modular tools box is their organ.
> The language is the way they say *this is mine, this is mine, this is mine*.
---
## See also
- [Acknowledgments](Acknowledgments) — partners and contributors
- [[Multi-Agent-Worktree]] — operational workflow for agents adding new
verbs without colliding
- [Hardware-Matrix](Hardware-Matrix) — boards on which the grammar runs
- In-repo: [`docs/grammar.md`](https://github.com/CyberMind-FR/secubox-deb/blob/master/docs/grammar.md),
[`HOWTO-grammar.md`](https://github.com/CyberMind-FR/secubox-deb/blob/master/HOWTO-grammar.md)