diff options
Diffstat (limited to '.agent')
| -rw-r--r-- | .agent/coding_standards.md | 65 | ||||
| -rw-r--r-- | .agent/config.md | 88 | ||||
| -rw-r--r-- | .agent/design.md | 71 | ||||
| -rw-r--r-- | .agent/mission.md | 21 | ||||
| -rw-r--r-- | .agent/narrative.md | 15 | ||||
| -rw-r--r-- | .agent/preferences.md | 22 | ||||
| -rw-r--r-- | .agent/worklog.md | 26 |
7 files changed, 308 insertions, 0 deletions
diff --git a/.agent/coding_standards.md b/.agent/coding_standards.md new file mode 100644 index 0000000..955ec35 --- /dev/null +++ b/.agent/coding_standards.md @@ -0,0 +1,65 @@ +# Coding Standards — modal-shell + +## Shell + +- **Default shell:** bash. Shebang is always `#!/usr/bin/env bash`. +- **Strict mode:** Every file starts with `set -euo pipefail`. No exceptions. +- **No bashisms in base.sh:** `base.sh` must also be compatible with zsh (users may source it from their zsh config). +- **Functions over repetition:** If the same logic appears in two modes, move it to `base.sh`. +- **No global side effects in sourced files:** `base.sh` sets env vars; it does not print output, start processes, or modify files. + +## Naming + +- Mode files: lowercase, hyphen-separated, `.sh` suffix. e.g. `db.sh`, `build.sh`, `reset.sh`. +- Variables in `base.sh`: `UPPER_SNAKE_CASE`. Exported. +- Local variables in mode files: `lower_snake_case`. Use `local` inside functions. +- The dispatcher: `ms` (no extension, executable). + +## Mode File Structure + +```sh +#!/usr/bin/env bash +# <one-line description of what this mode does> +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "$SCRIPT_DIR/base.sh" + +# mode logic here +``` + +## Confirmation Pattern for Destructive Modes + +```sh +echo "This will destroy and rebuild the environment." +read -rp "Continue? [y/N] " confirm +[[ "$confirm" =~ ^[Yy]$ ]] || { echo "Aborted."; exit 1; } +``` + +## Error Handling + +- Let `set -e` do the work. Do not swallow errors with `|| true` unless intentional and commented. +- On expected failure paths, print a helpful message to stderr before exiting: `echo "error: <message>" >&2` +- Do not use `exit 0` at the end of scripts — implicit success is fine. + +## Testing + +- Syntax check: `bash -n modes/<name>.sh` before committing any mode file. +- Dry-run: modes that exec into an environment can be tested with `bash -c 'source modes/base.sh && echo $PROJECT_ROOT'`. +- No automated test framework required for this project's scope. Manual verification is acceptable. + +## The Dispatcher (`ms`) + +- Must stay under 40 lines. +- No logic beyond: find the modes directory, match argument to filename, exec. +- If no argument: list available modes (strip `.sh`, sort). +- If unknown mode: print error to stderr, exit 1. +- Never source the mode file — always exec it (so the mode can itself exec into a shell without forking). + +## What Not to Do + +- No `eval`. +- No `set +e` blocks. +- No hardcoded paths outside of `base.sh`. +- No secrets in any file tracked by git. +- No modes that call other modes. diff --git a/.agent/config.md b/.agent/config.md new file mode 100644 index 0000000..af6c1fd --- /dev/null +++ b/.agent/config.md @@ -0,0 +1,88 @@ +# Agent Config — modal-shell +*Main entry point. Read this first, every session.* + +## Quick Links + +| File | Purpose | +|---|---| +| `worklog.md` | Session state: current focus, recently completed, next steps | +| `design.md` | Architecture overview and component map | +| `coding_standards.md` | Shell scripting conventions and testing | +| `mission.md` | Project goals and agent role | +| `narrative.md` | Background and history | +| `preferences.md` | User-specific preferences | +| `docs/adr/` | Architectural decision records | + +--- + +## Core Mandates + +### Safety Protocol + +1. **Inquiry-Only Default** — Treat every message as research or analysis unless it is an explicit, imperative instruction. +2. **Zero Unsolicited Changes** — Never modify files or scripts based on assumptions about intent. +3. **Strategy Checkpoint** — Research first. Present approach. Wait for explicit approval before touching anything outside `.agent/`. +4. **Verify State First** — Check current state (`ls`, `git status`, `cat` the relevant file) before proposing changes. +5. **Destructive Operations Require Confirmation** — Any change that deletes, overwrites, or resets state must be confirmed explicitly. + +### Living Documentation + +1. **Update `.agent/` continuously** — When decisions are made, patterns emerge, or preferences are revealed, update the relevant file immediately. +2. **Worklog at start and end** — `worklog.md` reflects what was done this session and what comes next. +3. **ADRs for architecture decisions** — Any significant structural or tooling decision gets an entry in `docs/adr/`. + +--- + +## Workflow + +``` +Research → Strategy → Execution +``` + +1. **Research** — Read the relevant mode files and base.sh. Understand the current pattern before proposing changes. +2. **Strategy** — Describe the change and why. For anything beyond a trivial edit, wait for a "go ahead." +3. **Execution** + - Make the change. + - Verify it works: run `ms <mode>` in a subshell or with `bash -n` for syntax. + - Update `worklog.md`. + +--- + +## Project Layout + +``` +modal-shell/ + ms # dispatcher (entry point for users) + .envrc # direnv: auto-sources base.sh on cd + modes/ + base.sh # sourced by all modes; env, secrets, PROJECT_ROOT + db.sh # database shell mode + build.sh # build pipeline mode + reset.sh # destructive rebuild mode (prompts for confirmation) + logs.sh # log streaming mode + docs/ + adr/ # architectural decision records + .agent/ # agent configuration (this directory) + CLAUDE.md # repo root entry point +``` + +--- + +## Essential Commands + +| Command | Action | +|---|---| +| `ms <mode>` | Enter a named mode | +| `ms` (no args) | List available modes | +| `bash -n modes/<mode>.sh` | Syntax-check a mode file | +| `direnv allow` | Trust `.envrc` after changes | +| `source modes/base.sh` | Manually load base env | + +--- + +## What NOT to Do + +- Do not add logic to the `ms` dispatcher beyond finding and executing mode files. +- Do not store secrets in any file in this repo. +- Do not create modes that silently do destructive things. +- Do not introduce dependencies that aren't already in the base environment. diff --git a/.agent/design.md b/.agent/design.md new file mode 100644 index 0000000..f17a80b --- /dev/null +++ b/.agent/design.md @@ -0,0 +1,71 @@ +# 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/<name>.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/<name>.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 diff --git a/.agent/mission.md b/.agent/mission.md new file mode 100644 index 0000000..96cf618 --- /dev/null +++ b/.agent/mission.md @@ -0,0 +1,21 @@ +# Mission + +## Core Purpose + +modal-shell is a lightweight, portable shell environment dispatcher. It encodes *intent* at the entry point — instead of remembering commands, you invoke a named mode and land directly in the right context for the task at hand. + +## Problem Being Solved + +Shell environments accumulate ambient state. Developers remember incantations. Onboarding is tribal knowledge. modal-shell replaces all of that with a `modes/` directory and a dumb dispatcher: if you can name what you're doing, you can enter that mode. + +## Strategic Values + +- **Composability over configuration** — modes layer on top of a shared base; no duplication. +- **Explicitness** — every mode declares its own environment. Nothing is implicit. +- **Portability** — works locally, in CI, in containers. Same modes everywhere. +- **Minimal footprint** — no framework, no daemon, no state. Just shell. +- **Safety for destructive operations** — modes that destroy things ask before proceeding. + +## Agent Role + +When working on this project, the agent is a careful shell scripter and tool designer. Changes should be surgical and composable. New modes follow the established pattern. The dispatcher stays dumb. Complexity lives in modes, never in the framework. diff --git a/.agent/narrative.md b/.agent/narrative.md new file mode 100644 index 0000000..f14998e --- /dev/null +++ b/.agent/narrative.md @@ -0,0 +1,15 @@ +# Narrative + +## Origin + +modal-shell began as four zsh scripts in a Vagrant-based PHP project circa ~2014. The original `up.zsh` booted a VM and SSH'd in; sibling scripts (`mysql.zsh`, `phing.zsh`) set `VAGRANT_OPTS` before delegating to it. The pattern was right — intent-at-entry-point — but the implementation was buried in a single project and tied entirely to Vagrant and Phing. + +## The Insight Worth Keeping + +The composition model — "set context, call the base" — is sound. What was wrong was everything specific to the stack: Vagrant, Phing, hardcoded paths, unprotected env vars for secrets, no confirmation on destructive operations. + +The modal concept maps cleanly to modern tooling. `vagrant up && vagrant ssh` becomes `docker compose exec` or `nix develop`. `VAGRANT_OPTS` becomes proper mode files with sourced base environments. Phing becomes `just` or `make`. + +## Current Phase + +Greenfield rewrite. The original repo (`thepeterstone/modal-shell`) is reference only. The new implementation lives at `/workspace/modal-shell` and follows the project conventions established here. diff --git a/.agent/preferences.md b/.agent/preferences.md new file mode 100644 index 0000000..a882e39 --- /dev/null +++ b/.agent/preferences.md @@ -0,0 +1,22 @@ +# Preferences + +*Living record. Update when new preferences are revealed.* + +## Interaction Style + +- Concise responses. No trailing summaries restating what was just done. +- Present strategy before execution for anything non-trivial. +- Ask when ambiguous rather than assuming. + +## Technical Preferences + +- bash over zsh for portability, but `base.sh` must be zsh-compatible for direct sourcing. +- `direnv` for automatic environment loading — preferred over manual `source` steps. +- Secrets via 1Password CLI (`op run --`) where available. +- `just` preferred over `make` for new task runners, but don't add it as a dep if the project doesn't already use it. + +## What to Avoid + +- Adding frameworks or dependencies that aren't already present. +- Clever shell tricks that obscure intent. Readable over terse. +- Modes that do more than one thing. diff --git a/.agent/worklog.md b/.agent/worklog.md new file mode 100644 index 0000000..7ef71c7 --- /dev/null +++ b/.agent/worklog.md @@ -0,0 +1,26 @@ +# Worklog + +## Current Focus + +Initial project setup. Directory structure, agent config files, mode stubs, and dispatcher are being created. + +--- + +## Session: 2026-03-27 — Project Initialization + +### Completed +- Created project at `/workspace/modal-shell` +- Established `.agent/` directory with full config suite +- Written ADR-001 (mode-as-intent architecture) +- Created `modes/` directory with `base.sh`, `db.sh`, `build.sh`, `reset.sh`, `logs.sh` stubs +- Created `ms` dispatcher script +- Created `.envrc` for direnv integration +- Created `.gitignore` + +### Next Steps +- Fill in `base.sh` for the specific target project/environment +- Customize mode stubs to match actual toolchain (`psql`/`mysql`, `docker compose`/`nix`, etc.) +- Run `direnv allow` after reviewing `.envrc` +- Add project-specific modes as needed + +--- |
