# Architecture — modal-shell ## Overview modal-shell is a three-layer system: ``` [ ms dispatcher ] → [ mode file ] → [ base.sh + runtime ] ``` 1. **`ms`** — dumb dispatcher. Reads `modes/` directory, matches argument to filename, executes. 2. **Mode files** — encode intent. Each sources `base.sh` and then does exactly one thing. 3. **`base.sh`** — shared environment foundation. Sets `PROJECT_ROOT`, loads secrets, configures toolchain. ## Component Map | Component | Role | |---|---| | `ms` | Dispatcher. Lists modes if no arg. Exits non-zero on unknown mode. | | `modes/base.sh` | Foundation. Sourced by all modes. Never executed directly. | | `modes/db.sh` | Opens an interactive database shell. | | `modes/build.sh` | Runs the build pipeline to completion. | | `modes/reset.sh` | Destroys and rebuilds the environment. Requires confirmation. | | `modes/logs.sh` | Streams runtime logs. | | `.envrc` | direnv hook. Sources `base.sh` automatically on `cd`. | ## Composition Model Every mode follows this pattern: ```sh #!/usr/bin/env bash set -euo pipefail source "$(dirname "$0")/base.sh" # mode-specific logic here ``` Modes do not call other modes. Modes do not share state with each other. If two modes need the same sub-behavior, that behavior belongs in `base.sh`. ## Data Flow ``` user: ms db ms → finds modes/db.sh modes/db.sh → source base.sh (sets PROJECT_ROOT, loads env) modes/db.sh → exec psql / mysql / redis-cli (as configured in base.sh) user lands in DB shell with correct credentials ``` ## Secrets Secrets are never stored in files. `base.sh` loads them at runtime via: - `op run --` (1Password CLI) — preferred - `doppler run --` — alternative - `.env` file sourced locally — acceptable for non-sensitive local dev only, never committed ## Adding a New Mode 1. Create `modes/.sh` 2. Start with the standard header (shebang + `set -euo pipefail` + `source base.sh`) 3. Implement the mode 4. Add a brief comment at the top describing intent 5. If destructive: add a confirmation prompt before proceeding 6. Run `bash -n modes/.sh` to verify syntax 7. Update `worklog.md` ## ADRs See `docs/adr/` for decisions on: - [ADR-001](../docs/adr/001-mode-as-intent.md) — Mode-as-intent architecture