Skip to content
Back to skills

Architecture

BSecurity

How leashd's core components fit together — build_engine wiring, the Engine message loop, the three-layer safety pipeline (gatekeeper/sandbox/policy/approval), the tmux agent runtime, the EventBus plugin system, config layering, and two-tier storage. Use when onboarding, planning a change that spans subsystems, or deciding where new code belongs.

  • 5 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 23, 2026
developmentrustbashsqlfastapigitapibackend

Works with

  • claude code
  • cli
  • api
  • mcp

Security analysis

B85/100
  • highPerforms destructive filesystem operations

Pro shows the line behind each finding and how to fix it

Scanned October 1, 2026

npx -y skills add vmehera123/leashd --skill architecture --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Architecture?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Architecture
[![Security: B — Skills Directory](https://www.skillsdirectory.com/api/skills/vmehera123-architecture/badge)](https://www.skillsdirectory.com/skills/vmehera123-architecture)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: architecture
description: How leashd's core components fit together — build_engine wiring, the Engine message loop, the three-layer safety pipeline (gatekeeper/sandbox/policy/approval), the tmux agent runtime, the EventBus plugin system, config layering, and two-tier storage. Use when onboarding, planning a change that spans subsystems, or deciding where new code belongs.
allowed-tools:
  - Read
  - Grep
  - Glob
  - Bash
---

# leashd architecture

Safety-first agentic coding daemon. Shape: **connectors → Engine → middleware → agent runtime**, with every tool call the agent makes intercepted by a **three-layer safety pipeline**, and an **EventBus** decoupling plugins. This skill is the mental model plus a file map.

> **Specs drift.** `specs/app/` has deeper numbered references, but they lag the code — `00-quick-reference.md` can still describe deleted modules (`auto_approver.py`, `task_v4.py`, …). Treat specs and `README.md` as starting points; **verify every claim against source before relying on it.**

## Request flow (one user message)

```
connector (web / telegram) → MultiConnector (chat_id routing)
  → Engine.handle_message → middleware chain (auth, rate limit)
    → agent runtime executes
      → each tool call → Gatekeeper: sandbox → policy → approval
  → streamed response back to the connector
```

## Bootstrap & wiring

`main.py:run()` → `cli.py` (argparse router, smart-start) → `main.py:start()` → one of `_run_cli` / `_run_telegram` / `_run_web` / `_run_multi` (chosen by which connectors are configured) → **`app.py:build_engine(config, connector)`**.

`build_engine` is the single wiring point. In order it constructs: logging → MCP server config → session store + message store (both global at `~/.leashd/`) → `SessionManager` → **`agent = get_agent(config.agent_runtime, config)`** → `EventBus` → `PolicyEngine` → `SandboxEnforcer` → `AuditLogger` → `create_builtin_plugins(...)` → approval + interaction coordinators (only when a connector exists) → middleware chain → git handler → `Engine(...)`.

## Components & where they live

| Concern | Entry point | Notes |
|---|---|---|
| Orchestration | `core/engine.py` (`Engine`) | message loop, streaming, command dispatch, auto-approve mgmt |
| Safety pipeline | `core/safety/gatekeeper.py` (`ToolGatekeeper`) | orchestrates sandbox → policy → approval for **every** tool call |
| ↳ sandbox | `core/safety/sandbox.py` (`SandboxEnforcer`) | path-scoped to approved dirs |
| ↳ policy | `core/safety/policy.py` + `policies/*.yaml` | allow / deny / require_approval; compound-bash split, deny-wins |
| ↳ approval | `core/safety/approvals.py` (`ApprovalCoordinator`) | human buttons or AI auto-approve |
| ↳ audit | `core/safety/audit.py` → `.leashd/audit.jsonl` | append-only decisions |
| Agent runtime | `agents/registry.py` + `agents/runtimes/tmux.py` / `tmux_session.py` | only `tmux` is registered since 2.0; new runtimes `register_agent()`; `build_engine(agent=)` takes any `BaseAgent` |
| Connectors | `connectors/{web,telegram,multi}.py` | `MultiConnector` routes by `chat_id` |
| Multi-conversation | `core/chat_sessions.py` + `connectors/telegram_sessions.py` | `/session` — N conversations in one chat, addressed `<chat>:s<n>` |
| Middleware | `middleware/{auth,rate_limit}.py` | run before the agent |
| Plugins / events | `core/events.py` (`EventBus`) + `plugins/registry.py` | pub/sub; `create_builtin_plugins()` registers builtins |
| Autonomous / task | `plugins/builtin/task_orchestrator.py`, `_task_prompts.py` | `/task`: implement → verify → opt-in review |
| Config | `core/config.py` (`LeashdConfig`), `config_store.py` | env prefix `LEASHD_` |
| Storage | `storage/{sqlite,memory}.py` | two-tier, see below |
| Web UI / hooks | `web/` (`app.py`, `routes.py`, `ws_handler.py`, `tmux_hooks.py`) | FastAPI; also hosts the tmux hook receiver |

## The safety pipeline (the core invariant)

Every tool call is intercepted **before it runs**:

1. **Sandbox** — reject paths outside `approved_directories`.
2. **Policy** — first-matching YAML rule → `allow` / `deny` / `require_approval`. Compound bash (`&&`, `||`, `;`) is split and evaluated segment-by-segment; **deny wins**.
3. **Approval** — `require_approval` → human buttons (interactive) or AI auto-approve (autonomous). Hard-denies (credentials, `rm -rf`, `sudo`, force-push) **can never be overridden** by any approver.

In the `tmux` runtime interception happens via Claude Code PreToolUse hooks rather than in-process — see the **`tmux-runtime`** skill.

## Config layering

`~/.leashd/config.yaml` → project `.env` → environment variables (highest priority). `config_store.py:inject_global_config_as_env()` bridges YAML → `os.environ` so pydantic-settings (`LeashdConfig`, prefix `LEASHD_`) picks them up. Inspect the resolved view with `leashd config`.

## Storage (two tiers, both global at `~/.leashd/`)

- **`sessions.db`** — user↔directory mapping, session IDs, costs, and the **`task_runs`** table. Never switches with `/dir`.
- **`messages.db`** — conversation history (cost + duration per message).
- **`audit.jsonl`** — pinned to `approved_directories[0]`, **not** the working directory.

`LEASHD_STORAGE_BACKEND=memory` for tests.

## Plugins & events

Subsystems decouple via `EventBus` pub/sub (events like `tool.allowed`, `approval.requested`, `task.submitted`). Plugins implement `LeashdPlugin` (lifecycle `initialize → start → stop`) and are registered in `create_builtin_plugins()`. Builtins: audit, browser-tools, web-agent, web-interaction-logger, merge-resolver, plus the conditional `TaskOrchestrator`.

## Removed (don't trust stale docs)

1.0 deleted the v1/v2 orchestrator + "conductor", `auto_approver.py`, `auto_plan_reviewer.py`, `agentic_orchestrator.py`, `_cli_evaluator.py` and `core/context_manager.py`. 2.0 deleted the `claude-cli`, `claude-code` (Agent SDK) and `codex` runtimes (the registry stays, with `tmux` alone registered), `task_v3.py`/`task_v4.py` (merged into `task_orchestrator.py`) and the `/test` runner. `specs/app/` may still mention them. **Source of truth: `plugins/registry.py` + `plugins/builtin/`.**

## Verify, then change

Use `codebase-memory-mcp` for structural lookups (`search_graph`, `trace_path`, `get_code_snippet`), then **`Read` the file before editing** — the graph and the specs can both lag the tree. Run `make check` after (see CLAUDE.md for the E2E/JS tiers it skips).

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.