Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
e494595
chore(lint): add .oxlintrc.json with type-aware rules
ApiliumDevTeam Jul 13, 2026
010ffea
docs(security): document dependency supply-chain policy
ApiliumDevTeam Jul 13, 2026
d26e021
docs(security): add trust model — OS isolation as the load-bearing bo…
ApiliumDevTeam Jul 13, 2026
f2da992
ci: enforce lockfile change policy
ApiliumDevTeam Jul 13, 2026
f49188b
refactor: replace all non-test as-any casts with proper types
ApiliumDevTeam Jul 13, 2026
9212ff3
feat(agents): prompt cache discipline + system-prompt drift detection
ApiliumDevTeam Jul 13, 2026
499cd76
docs: TUI redesign audit and roadmap
ApiliumDevTeam Jul 13, 2026
debe72a
Stabilization pass: lint config, type safety, security docs, cache ob…
ApiliumDevTeam Jul 13, 2026
1a11439
deps: migrate pi agent suite to @earendil-works scope (#66)
ApiliumDevTeam Jul 13, 2026
fdf6b51
deps: bump agent stack to 0.80.6 and refresh runtime dependencies (#68)
ApiliumDevTeam Jul 13, 2026
bb5e966
Terminal UI: accessible-mode parity, robustness, and visual consisten…
ApiliumDevTeam Jul 13, 2026
4e7527d
Terminal UI: streaming performance, auto-theme, and per-section visib…
ApiliumDevTeam Jul 13, 2026
ea1b5b4
feat(tui): disable vim mode and remove dead code (#70)
ApiliumDevTeam Jul 14, 2026
1a2b8fa
Theme system v2: custom palettes, colorblind presets, and monochrome …
ApiliumDevTeam Jul 14, 2026
583891e
TUI: cross-platform clipboard, inline images, and helper extraction (…
ApiliumDevTeam Jul 14, 2026
410223f
FTS5 session search and skill curator lifecycle (#77)
ApiliumDevTeam Jul 14, 2026
48af542
TUI: deep split of tui.ts and tui-command-handlers.ts (#78)
ApiliumDevTeam Jul 14, 2026
b7c4727
fix(search): break circular dependency that crashed the CLI
ApiliumDevTeam Jul 14, 2026
be0f508
chore(plugins): sync extension versions to 0.3.2
ApiliumDevTeam Jul 14, 2026
1110dbf
docs: complete changelog and README for 0.4.0
ApiliumDevTeam Jul 14, 2026
3371bf6
feat: quality gates for 0.4.0 — remove vim from help, fix version res…
ApiliumDevTeam Jul 14, 2026
c4e9b02
release: 0.4.0
ApiliumDevTeam Jul 14, 2026
737cc5c
chore(plugins): sync extension versions to 0.4.0
ApiliumDevTeam Jul 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
6 changes: 6 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
with:
# Full history so the lockfile policy check can read commit messages.
fetch-depth: 0
submodules: false

- name: Setup Node environment
Expand All @@ -114,6 +116,10 @@ jobs:
- name: Check types, lint, and format
run: pnpm check

- name: Enforce lockfile change policy
if: github.event_name == 'pull_request'
run: node scripts/check-lockfile-policy.mjs --base "origin/${{ github.base_ref }}" --head "${{ github.event.pull_request.head.sha }}"

build-artifacts:
needs: [docs-scope, changed-scope, check]
if: needs.docs-scope.outputs.docs_only != 'true' && (github.event_name == 'push' || needs.changed-scope.outputs.run_node == 'true')
Expand Down
43 changes: 43 additions & 0 deletions .oxlintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"categories": {
"correctness": "warn"
},
"rules": {
"no-explicit-any": "warn",
"typescript/no-floating-promises": "warn",
"typescript/no-misused-promises": "warn",
"typescript/await-thenable": "warn",
"typescript/no-base-to-string": "warn",
"typescript/restrict-template-expressions": "warn",
"typescript/no-misused-spread": "warn",
"typescript/no-this-alias": "warn",
"no-unused-vars": "warn",
"no-unassigned-vars": "warn",
"no-dupe-keys": "warn",
"no-unused-expressions": "warn",
"no-misleading-character-class": "warn",
"no-control-regex": "warn",
"no-new-array": "off"
},
"overrides": [
{
"files": [
"**/*.test.ts",
"**/*.e2e.test.ts",
"**/*.live.test.ts",
"**/*.test-helpers.ts",
"**/test-helpers/**",
"**/test-utils/**"
],
"rules": {
"typescript/no-floating-promises": "off",
"typescript/no-misused-promises": "off",
"typescript/unbound-method": "off",
"no-explicit-any": "off",
"typescript/no-base-to-string": "off",
"typescript/restrict-template-expressions": "off"
}
}
]
}
10 changes: 10 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,16 @@
- Aim to keep files under ~700 LOC; guideline only (not a hard guardrail). Split/refactor when it improves clarity or testability.
- Naming: use **Mayros** for product/app/docs headings; use `mayros` for CLI command, package/binary, paths, and config keys.

## Prompt Cache Discipline

Per-conversation prompt caching is sacred. A long-lived session reuses a cached prefix on every turn; anything that mutates past context, swaps toolsets, or rebuilds the system prompt with volatile content invalidates that cache and multiplies token cost. The project enforces caching via the `cacheRetention` stream option (handled by the provider layer), and the cost of an invalidation is real and silent.

- The system prompt is rebuilt on every run. Its content must be **stable across runs that have no reason to change it**. Do not add volatile data (timestamps that tick every second, random IDs, unordered maps) to the system prompt or to context files that feed it. The `Runtime:` line is the sanctioned place for run-scoped info and is designed to change only when the operator changes model, channel, or thinking level.
- Slash commands that mutate prompt-relevant state (`/model`, `/think`, `/reasoning`, `/elevated`, `/fast`, `/new`) are expected to invalidate the cache on the **next** turn by design. That is the only acceptable invalidation. A change that invalidates the cache mid-turn, or on every turn regardless of whether the operator touched anything, is a bug.
- When adding context to the prompt (new sections, hook output, injected memory), prefer **append-only** structure. Reordering existing sections or inserting in the middle invalidates everything after the insertion point.
- Hooks (`before_prompt_build`, `before_agent_start`) that override `systemPrompt` or `prependContext` must be deterministic for a given input. A hook that returns different text on consecutive calls with the same inputs breaks the cache and is a high-priority bug.
- The `diagnostics.cacheTrace` subsystem records a SHA-256 of the system prompt and messages at each pipeline stage. When investigating cache regressions, compare `systemDigest` across consecutive turns of a session where nothing should have changed — a drift there is the signature of a cache-breaking change.

## Release Channels (Naming)

- stable: tagged releases only (e.g. `vYYYY.M.D`), npm dist-tag `latest`.
Expand Down
79 changes: 79 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,85 @@ Product: https://apilium.com/us/products/mayros
Download: https://mayros.apilium.com
Docs: https://apilium.com/us/doc/mayros

## 0.4.0 (2026-07-14)

Major release: FTS5 session search, theme system v2, complete TUI redesign, skill curator lifecycle, and migration to the official agent stack.

### Changes

- **FTS5 session search** — dedicated SQLite full-text index with BM25 ranking, multi-word queries, role/timestamp/session filters, and snippet generation. Falls back to linear substring scan when `node:sqlite` is unavailable.
- **Theme system v2** — 13 built-in themes including colorblind-optimized (Okabe-Ito) and monochrome palettes. Custom themes from `~/.mayros/themes/*.json`. Auto-detection of terminal dark/light preference via DSR color-scheme query.
- **Inline image rendering** — tool results with image content blocks now display inline in terminals that support the Kitty graphics or iTerm2 inline image protocols, with text fallback for unsupported terminals.
- **Cross-platform clipboard** — `/copy` and image paste now work on Windows (PowerShell), Wayland (wl-paste), and WSL (clip.exe) via a unified fallback chain.
- **Per-section detail visibility** — tools (Ctrl+O) and thinking (Ctrl+T) each cycle independently through hidden → collapsed → expanded states.
- **Incremental streaming markdown** — assistant messages split at the last stable block boundary, turning per-delta render cost from O(n²) into O(n).
- **Skill curator lifecycle** — automatic activity tracking and lifecycle transitions (active → stale after 30 days, archived after 90 days). Only agent-created skills are auto-archived; pinned skills are never touched.
- **Extended keyboard protocols** — Kitty keyboard protocol and xterm modifyOtherKeys enabled in capable terminals for reliable modifier-key combinations.
- **Prompt cache drift detection** — system-prompt digest tracked across turns; a `cache:system-drift` event is emitted when the digest changes unexpectedly.
- **Accessible TUI command parity** — `/abort`, `/new`, `/compact`, `/status`, `/model`, `/session`, and `/help` now work in accessible (screen-reader) mode via a shared command core.
- **Agent stack migrated** to the official `@earendil-works/*@0.80.6` scope with zod deduplication and 21 refreshed runtime dependencies.
- **Terminal UI modularized** — `tui.ts` split from 1087 to 591 LOC, `tui-command-handlers.ts` split from 1402 to 351 LOC across focused modules.

### Fixes

- Ctrl+C now aborts the active run (tri-state: abort → clear input → exit on double-press).
- Accessibility TUI readline temporal-dead-zone crash fixed.
- CLI and TUI palettes unified (same accent color across all surfaces).
- Diff renderer respects active theme colors (correct under light/high-contrast themes).
- 20 `as any` casts in production code replaced with proper types.
- Lockfile change policy enforced in CI (deps-scoped commits required for lockfile changes).

### Internal

- Oxlint type-aware rules formalized (`.oxlintrc.json`).
- Security trust model and dependency supply-chain policy documented in `SECURITY.md`.
- Dead code removed: vim handler (779 LOC), input-history store.
- Silent `catch {}` blocks migrated to subsystem logger.

### Breaking changes

- **Vim mode removed.** The bridge connecting vim motions to the editor buffer was never wired and the rendering dependency does not expose the cursor API needed to fix it cleanly. The `/vim` command now reports the feature is unavailable. Emacs/readline-style keybindings (Ctrl+A/E/W/U/K) remain active.
- **Agent dependency scope changed** from `@mariozechner/*@0.54.0` to `@earendil-works/*@0.80.6`. Extension authors importing these internals must update imports.
- **CLI palette accent changed** from orange (`#FF5A2D`) to gold (`#F6C453`) to match the TUI identity.

---

## 0.3.2 (2026-03-30)

Installer UX improvements, security patches, and CI repair.

- macOS installer: Terminal-based setup with visible progress, branded DMG
- All installers: skip onboard for portal wizard, gateway.auth.mode=none, gateway install step
- Agent onboarding: user names their agent (default: Atlas)
- Resolve all 21 Dependabot security vulnerabilities
- Fix CI workflow and PR Review action
- Cap CI test workers to 2 to prevent runner timeout

---

## 0.3.1 (2026-02-21)

Desktop installers, Mamoru security layer, and Mayrito rebrand.

- Desktop installers for Windows (.exe), macOS (.dmg), and Linux (.AppImage/.deb) that bundle Node.js + Cortex
- Mamoru (守る) security layer: sandbox probing, egress gate, secrets vault, API keys, local model support
- GPU detection and guided Ollama/vLLM model installation
- 50+ model catalog segmented by activity with VRAM-aware filtering

---

## 0.3.0 (2026-02-16)

Kaneru — AI venture management system.

- Ventures, missions, squads, Q-learning routing, fuel control, and decision audit
- 24 MCP tools for venture management
- Web portal with ventures tab, mission kanban, chain of command tree
- Setup Wizard for guided venture creation
- Semantic DAG integration with Ed25519 signatures

---

## 0.2.1 (2026-03-14)

Memory health tools — conflict detection and digest summaries for proactive memory maintenance.
Expand Down
31 changes: 17 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,26 +154,29 @@ mayros -p "refactor auth flow" # headless mode (non-interactive)

**Features:**

- 🎨 3 themes (dark, light, high-contrast) — `/theme`
- 🎨 13 built-in themes (dark, light, high-contrast, colorblind, monochrome, + more) + custom themes — `/theme`
- 📝 3 output styles (standard, explanatory, learning) — `/style`
- ⌨️ Vim mode with motions, operators, undo — `/vim`
- 📋 `Ctrl+V` image paste from clipboard
- 📊 `/diff` inline diff viewer · `/context` token usage chart
- 🌗 Auto-detection of terminal dark/light preference
- 📋 `Ctrl+V` image paste · inline image rendering in tool results (Kitty/iTerm2)
- 📊 `/diff` inline diff viewer (theme-aware) · `/context` token usage chart
- 🗺️ `/plan` semantic plan mode (Cortex-backed)
- 📎 `/copy` to clipboard · `/export [file]` to disk
- 📎 `/copy` to clipboard (cross-platform) · `/export [file]` to disk
- 🔀 `/model` switch models · `/think` set thinking level · `/fast` toggle fast mode
- 🔍 `mayros search` — FTS5 full-text search across sessions with BM25 ranking
- 🎛️ Per-section detail visibility (Ctrl+O tools, Ctrl+T thinking: hidden/collapsed/expanded)
- ⌨️ Extended keyboard protocols (Kitty/modifyOtherKeys) in capable terminals

**Slash commands (30+):**

| Command | Description | Command | Description |
| ---------------- | ----------------- | ---------------- | -------------------- |
| `/help` | List all commands | `/plan` | Semantic plan mode |
| `/new` | Reset session | `/diff` | Show pending changes |
| `/compact` | Compact context | `/context` | Token usage chart |
| `/think <level>` | Set thinking | `/theme` | Cycle themes |
| `/model <name>` | Switch model | `/vim` | Toggle vim mode |
| `/permission` | Permission mode | `/copy` | Copy last response |
| `/fast` | Fast mode | `/export [file]` | Export session |
| Command | Description | Command | Description |
| ---------------- | ----------------- | ------------- | -------------------- |
| `/help` | List all commands | `/plan` | Semantic plan mode |
| `/new` | Reset session | `/diff` | Show pending changes |
| `/compact` | Compact context | `/context` | Token usage chart |
| `/think <level>` | Set thinking | `/theme` | Cycle themes |
| `/model <name>` | Switch model | `/permission` | Permission mode |
| `/fast` | Fast mode | `/copy` | Copy last response |
| `/export [file]` | Export session | `/context` | Token usage chart |

**Markdown-driven extensibility:**

Expand Down
92 changes: 92 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,48 @@ Mayros security guidance assumes:
- Anyone who can modify `~/.mayros` state/config (including `mayros.json`) is effectively a trusted operator.
- A single Gateway shared by mutually untrusted people is **not a recommended setup**. Use separate gateways (or at minimum separate OS users/hosts) per trust boundary.

## Trust Model

The single load-bearing security boundary in Mayros is **operating-system level
isolation**. Everything else is a heuristic or a convenience, not a containment
boundary.

This distinction matters because it is easy to over-trust in-process defenses.
The rule below governs how each layer should be treated:

### What is and is not a boundary

- **Real boundaries** — mechanisms the OS or kernel enforces against a
malicious process running inside them:
- Separate OS users, containers, VMs, namespaces, seccomp, Landlock.
- A sandboxed Docker container with `--cap-drop=ALL --read-only`.
- A separate host entirely (the strongest option).
- **In-process defenses** — useful, but **not containment**. A sufficiently
resourced attacker who has code execution inside the process can bypass them:
- The approval gate and interactive permission prompts.
- Output redaction and secret masking (`src/security/output-masking.ts`).
- The static skill scanner and bash command blocklist.
- Rate limiters, query/write caps, and the enrichment timeout.
- The WASM skill sandbox (it narrows the attack surface of untrusted skill
code, but the host process can still be reached via bugs in the runtime).

Treat the in-process defenses as **defense in depth and attack-surface
reduction**, never as the thing that stops a determined adversary. The thing
that stops a determined adversary is running the untrusted workload under a
real OS boundary.

### Practical implications

- For fully untrusted skills, plugins, or tool output, run the Gateway (or the
session) inside a container or separate OS user. Do not rely on the approval
gate alone.
- The default loopback-only bind is a real boundary against remote network
attackers; keep it unless you have a replacement boundary (Tailscale, SSH
tunnel, firewall).
- When reviewing a security finding, classify it by which boundary it crosses.
A bug that lets a plugin read another plugin's memory is contained by the OS
user; a bug that lets a remotely-reached endpoint execute code is not.

## Plugin Trust Boundary

Plugins/extensions are loaded **in-process** with the Gateway and are treated as trusted code.
Expand Down Expand Up @@ -123,6 +165,56 @@ docker run --read-only --cap-drop=ALL \
mayros/mayros:latest
```

## Dependency Supply Chain

Mayros treats its dependency tree as part of its trust boundary. A malicious or
broken transitive package reaches users the moment it enters the lockfile, so the
project enforces the following controls in `package.json`:

### Release age floor

`pnpm.minimumReleaseAge: 2880` (48 hours) gates every resolution. A package
published less than 48 hours ago is not eligible for install, which buffers
against compromised or yanked releases that get quarantined shortly after
publish.

### Forced security overrides

The `pnpm.overrides` map forces specific versions of transitive dependencies
known to carry security regressions. Each override exists because a transitive
in the tree resolved to a vulnerable version and the override is the most
durable way to pin the patched floor without waiting for upstreams to bump.

When adding or changing an override, record why in the commit message: the CVE
or GHSA it addresses (or the regression it prevents). Overrides without a
recorded rationale are rejected in review.

### Patched dependencies

Any dependency declared in `pnpm.patchedDependencies` must use an exact version
(no `^` or `~`). This is a hard rule: a range on a patched package lets a future
resolve drift past the patch, silently reverting the fix.

### Lockfile discipline

The npm/pnpm lockfile pins the full transitive tree by content hash. Treat the
lockfile as a reviewed artifact, not an auto-generated one:

- A change to `pnpm-lock.yaml` without a corresponding dependency change in
`package.json` is suspicious and must be explained in the commit.
- Dependabot/Renovate PRs that bump a transitive without a recorded CVE/fix are
held until the change is understood.
- `pnpm install --frozen-lockfile` is the canonical install command in CI;
`pnpm install` (which can mutate the lockfile) is reserved for local
dependency changes that are committed alongside a `deps:` commit.

### Native build scripts

`pnpm.onlyBuiltDependencies` enumerates the packages allowed to run native
build scripts (node-gyp, prebuilt binaries). Packages not in this list cannot
execute install scripts, which limits the blast radius of a compromised native
dependency.

## Security Scanning

This project uses `detect-secrets` for automated secret detection in CI/CD.
Expand Down
2 changes: 1 addition & 1 deletion apps/macos/Sources/Mayros/ModelCatalogLoader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ enum ModelCatalogLoader {
]
for root in roots {
let candidate = root
.appendingPathComponent("node_modules/@mariozechner/pi-ai/dist/models.generated.js")
.appendingPathComponent("node_modules/@earendil-works/pi-ai/dist/models.generated.js")
if FileManager().isReadableFile(atPath: candidate.path) {
return candidate.path
}
Expand Down
2 changes: 1 addition & 1 deletion docs/concepts/oauth.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ mayros models status

## OAuth exchange (how login works)

Mayros’s interactive login flows are implemented in `@mariozechner/pi-ai` and wired into the wizards/commands.
Mayros’s interactive login flows are implemented in `@earendil-works/pi-ai` and wired into the wizards/commands.

### Anthropic (Claude Pro/Max) setup-token

Expand Down
2 changes: 1 addition & 1 deletion docs/gateway/doctor.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ Current migrations:
### 2b) OpenCode Zen provider overrides

If you’ve added `models.providers.opencode` (or `opencode-zen`) manually, it
overrides the built-in OpenCode Zen catalog from `@mariozechner/pi-ai`. That can
overrides the built-in OpenCode Zen catalog from `@earendil-works/pi-ai`. That can
force every model onto a single API or zero out costs. Doctor warns so you can
remove the override and restore per-model API routing + costs.

Expand Down
12 changes: 6 additions & 6 deletions docs/pi.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ Mayros uses the pi SDK to embed an AI coding agent into its messaging gateway ar

```json
{
"@mariozechner/pi-agent-core": "0.49.3",
"@mariozechner/pi-ai": "0.49.3",
"@mariozechner/pi-coding-agent": "0.49.3",
"@mariozechner/pi-tui": "0.49.3"
"@earendil-works/pi-agent-core": "0.49.3",
"@earendil-works/pi-ai": "0.49.3",
"@earendil-works/pi-coding-agent": "0.49.3",
"@earendil-works/pi-tui": "0.49.3"
}
```

Expand Down Expand Up @@ -164,7 +164,7 @@ import {
DefaultResourceLoader,
SessionManager,
SettingsManager,
} from "@mariozechner/pi-coding-agent";
} from "@earendil-works/pi-coding-agent";

const resourceLoader = new DefaultResourceLoader({
cwd: resolvedWorkspace,
Expand Down Expand Up @@ -504,7 +504,7 @@ Mayros also has a local TUI mode that uses pi-tui components directly:

```typescript
// src/tui/tui.ts
import { ... } from "@mariozechner/pi-tui";
import { ... } from "@earendil-works/pi-tui";
```

This provides the interactive terminal experience similar to pi's native mode.
Expand Down
Loading
Loading