- client: stdio + Streamable HTTP transports, 2025-11-25
handshake/list/call/ping, vault mcp_servers with sealed headers,
per-profile enable, description-hash pins, tool cache
- mcp_normalize: pasted JSON/TOML configs (type repair, ${VAR}
expansion from env then vault secrets, allow/deny lists);
github URLs resolve via registry/package/README with live
handshake verification before storing
- bridge: enabled tools enter lazy select_tools as
mcp_<server>_<tool>, dispatch fallback, approval like non-safe
shell, drift re-prompt, 64KB spill, per-call audit
- 7 agent tools: mcp_add/list/enable/disable/remove/tools/call
(native count 42->60 in README, was already stale at 53)
- server: --serve-mcp KEY (+ --mcp-port/--mcp-bind) serves all 60
native tools plus chat (agent turn, per-session history) and
completions (stateless, current model) over single-threaded
HTTP with Bearer auth, sessions, idle expiry; yolo documented
- rotation + plaintext-boot refusal cover sealed headers
- mcp.md contract with drift tests; 47 new tests; live loopback
verified (client->serve over real HTTP)
86 lines
7.6 KiB
Markdown
86 lines
7.6 KiB
Markdown
# AGENTS.md
|
|
|
|
## Conventions
|
|
|
|
- Use plain `import` and `from` statements in Python files.
|
|
- Use the `.py` extension for Python source and test files.
|
|
- `tai.py` is the entire product in one standalone stdlib-only file: CLI entry plus the stable `import tai` surface, grouped into classes (instance classes for stateful clusters, static utility classes for stateless groups). It must import nothing outside the standard library; a bare copy of the file has to import and run anywhere. Canonical patch targets are `tai.<Class>.<name>` (or the module attribute for module-level data).
|
|
- There are two kinds of test, in two different places, on purpose — see "Testing" below for the full split. In short: unit tests are top-level `test_*.py`; integration tests are `tests/<topic>.py` (no `test_` prefix) built on `tai_test.py`.
|
|
- The in-`tai.py` TUI framework is documented in [tui.md](tui.md) — read it before touching any `Tui*` code.
|
|
- The grr terminal client (`tai.py --tui`, the `Grr*` classes) is specified in [grrtui.md](grrtui.md): read it before touching any `Grr*` code, and keep its screen, key and cap tables in step with the code (`GrrSpecTests` fails when they drift). It is a client of the grr server and shows what the server's `/api/spec` and `/locales.json` say; never copy a string, color or limit of the server into `tai.py`. `tests/grr_tui.py` drives the real binary against a real grr server (sibling `../grr`, `GRR_DIR` to move it) and a real model.
|
|
- The terminal multiplexer (`Mplex*` classes, `tai.py --mplex`, `~/.tai/mplex.toml`) is specified in [mplex.md](mplex.md): read it before touching any `Mplex*` code, and keep its option, command and key tables in step with the code (`MplexSpecTests` fails when they drift).
|
|
- Interactive UI flows (`plexer_show`, `PlexerFlow`, `PlexerController.ask`, the `show`/`result`/`cancel` control commands) are specified in [uiflow.md](uiflow.md): read it before touching any flow code, and keep its contract and cap tables in step with the code (`UiflowDocTests` fails when they drift).
|
|
- CAP protocol support (`Cap*` classes, `--cap-manifest`, `--cap-speak`, orchestrator drivers) is specified in [cap.md](cap.md): read it before touching any `Cap*` code, and keep its event, error and manifest tables in step with the code (`CapDocTests` fails when they drift).
|
|
- MCP support (`Mcp*` classes, `mcp_*` tools, `--serve-mcp`) is specified in [mcp.md](mcp.md): read it before touching any `Mcp*` code, and keep its wire, caps, and tool tables in step with the code (`McpDocTests` fails when they drift).
|
|
- Skills (`discover_skills`, `SKILL_BLUEPRINTS`, `BUNDLED_SKILLS`, the `skills` install target) are specified in [skills.md](skills.md): read it before touching skill code or embedded skill text, and keep its bundled-skill and adaptation tables in step with the code (`BundledSkillsTests` fails when they drift).
|
|
- Settings (`SETTINGS_CATALOG`, the `settings` table, `get_or_create_settings`/`upsert_settings`/`get_all_settings`, `boot_settings`) are specified in [settings.md](settings.md): read it before touching settings code, and keep its catalog table in step with the code (`SettingsTests` fails when they drift).
|
|
|
|
## Testing
|
|
|
|
**Unit tests**: `test_tai.py`, `test_seal.py`, at the repository top level, named `test_*.py`, `unittest`-based, import `tai.py` as a module directly, no subprocess, fast. `python3 test_tai.py` / `python3 test_seal.py`, or a single test via `python3 -m unittest test_tai.SomeClass.test_method`.
|
|
|
|
**Integration tests**: `tests/<topic>.py` (e.g. `tests/rag.py`), deliberately *not* named `test_*.py` and *not* at the top level, so the two kinds are never confused. These drive the real `tai.py` binary as a subprocess (one-shot or REPL) and check actual CLI behavior, using `tai_test.py` (the framework, at the repository root) as the one and only base to build on — never a one-off `subprocess`/`asyncio` harness per file. **They must exercise a real LLM call through the real binary — never a mocked model or a database write standing in for what the agent would have done; the resulting flakiness from a free, rotating backend is accepted, not engineered away.** Full conventions, that rule's full rationale, the required isolation rule (always a throwaway `TAI_HOME`), and why verification must check vault state rather than scrape CLI rendering, are in [tests/README.md](tests/README.md) — read it before adding a new one. Run with `python3 tests/<topic>.py` (`--filter`, `--interactive`, `--timeout` all supported).
|
|
|
|
## Profiles and bots
|
|
|
|
- A **profile** is a user-created identity (`--profile NAME`, `/profile NAME`); `default` is the fallback when none is given. Each profile owns a separate slice of every vault table; the only cross-profile knowledge is the identity list itself.
|
|
- A **bot** is a role inside one profile. Every profile starts with `main`; more are added with `create_bot`. There are no built-in bots.
|
|
|
|
## Key Features
|
|
|
|
- Autonomous decision making
|
|
- Multi-profile support
|
|
- Background subagent orchestration
|
|
- Secure vault storage
|
|
- Container sandbox support
|
|
- Progress tracking
|
|
- Interactive REPL
|
|
- Command-line interface
|
|
|
|
## Usage Examples
|
|
|
|
1. Start the main agent:
|
|
```bash
|
|
./tai.py
|
|
```
|
|
|
|
2. Use a specific profile:
|
|
```bash
|
|
./tai.py --profile work
|
|
```
|
|
|
|
3. Run a one-shot command:
|
|
```bash
|
|
./tai.py what is 2+3, use the shell
|
|
```
|
|
|
|
4. Check agent status:
|
|
```bash
|
|
./tai.py --version
|
|
```
|
|
|
|
5. Install the agent:
|
|
```bash
|
|
./tai.py --install
|
|
```
|
|
|
|
## Development Guidelines
|
|
|
|
- Write clear, concise code
|
|
- Follow Python conventions
|
|
- Test thoroughly
|
|
- Use the agent for documentation
|
|
- Keep code maintainable
|
|
- Document decisions
|
|
- Version control changes
|
|
- Collaborate effectively
|
|
|
|
## Command Output Rule
|
|
|
|
Every command an agent runs for the user (shell, ssh, sandbox box) **must stream live to the user in both modes**, in addition to being returned to the agent. It is a message, not a blocking spinner: a fixed-height window (REPL `LiveStream`, chat TUI `live` block) that keeps scrolling its last lines in place while the user keeps chatting. If the command stops on a prompt (sudo, ssh, y/n), it runs on a pty and asks the user through the same channel as `ask_user` (`agent.prompter` / REPL `input`); the answer is typed into the command, a decline sends end-of-file, and waiting for the user never counts against the timeout. Any new tool that runs a process must go through `run_live` with `Tools.shell_stream` and `Tools.shell_ask`, never a bare `subprocess.run`. Details: [tui.md](tui.md) (chat scene).
|
|
|
|
## Research Rule
|
|
|
|
All external research conducted for this project (web searches, reading documentation to settle a design question, competitive/prior-art analysis) is archived under `research/`, maintained under the auspices of the **Molodetz Institute — Research & Retrieval Division**. The full specification — folder layout, the three required document types (Source Dossier, Source Citation Card, Conclusion Document), required metadata, and the quality bar — lives in [research/README.md](research/README.md); [research/INDEX.md](research/INDEX.md) is the living registry and statistics page. Read [research/README.md](research/README.md) in full before writing into this archive.
|
|
|
|
The binding rule, in short: **a research task is not done until it is written into `research/`.** Every source actually consulted gets its own document (Tier 1 if read and synthesized, Tier 2 if only seen in a result listing — never skipped, never inflated past what's actually known), every decision the research produced gets its own Conclusion document in that subject's `conclusions/` folder, and `research/INDEX.md` gets updated in the same pass. Check `research/INDEX.md` for an existing subject before opening a new one. |