Compare commits

...

40 Commits

Author SHA1 Message Date
417805f330 fix: bump memory/queue/storage to 0.0.4 to force republish (#423)
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/publish Pipeline was successful
ci/woodpecker/tag/publish Pipeline was successful
2026-04-05 14:39:15 +00:00
2472ce52e8 fix: bump stale sub-package versions (brain/forge/log) (#422)
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/publish Pipeline was successful
2026-04-05 14:26:30 +00:00
597eb232d7 fix: revert mosaic to 0.0.22 alpha + republish macp (#421)
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/publish Pipeline was successful
2026-04-05 14:15:46 +00:00
afe997db82 docs: mission cli-unification-20260404 complete (#420)
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/publish Pipeline was successful
2026-04-05 07:54:50 +00:00
b9d464de61 docs: CLI unification release v0.1.0 (M8) (#419)
Some checks failed
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/publish Pipeline failed
ci/woodpecker/tag/publish Pipeline was successful
2026-04-05 07:46:00 +00:00
872c124581 feat(mosaic): unified first-run UX wizard -> gateway install -> verify (#418)
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/publish Pipeline was successful
2026-04-05 07:29:17 +00:00
a531029c5b feat(mosaic): mosaic telemetry command (M6 CU-06-01..05) (#417)
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/publish Pipeline was successful
2026-04-05 07:06:42 +00:00
35ab619bd0 docs: session 2 orchestrator bookkeeping (M3/M4/M5 complete) (#416)
Some checks failed
ci/woodpecker/push/ci Pipeline failed
ci/woodpecker/push/publish Pipeline failed
2026-04-05 07:06:40 +00:00
831193cdd8 fix(macp): align exports + add CLI smoke test (#415)
Some checks failed
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/publish Pipeline failed
2026-04-05 06:57:42 +00:00
df460d5a49 feat(macp): mosaic macp CLI surface (#410)
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/publish Pipeline was successful
2026-04-05 06:33:52 +00:00
119ff0eb1b fix(mosaic): gateway token recovery review remediations (#414)
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/publish Pipeline was successful
2026-04-05 06:13:29 +00:00
3abd63ea5c Merge pull request 'feat(mosaic): mosaic auth CLI surface' (#413) from feat/mosaic-auth-cli into main
Some checks failed
ci/woodpecker/push/publish Pipeline failed
ci/woodpecker/push/ci Pipeline failed
2026-04-05 06:11:33 +00:00
641e4604d5 feat(forge): mosaic forge CLI surface (#412)
Some checks failed
ci/woodpecker/push/publish Pipeline failed
ci/woodpecker/push/ci Pipeline failed
2026-04-05 06:08:50 +00:00
Jarvis
9b5ecc0171 feat(mosaic): add auth command and stage parallel agent changes
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/pr/ci Pipeline was successful
Picks up auth command and spec written by parallel agent, and updated
mosaic cli.ts wiring from parallel development during cli-unification.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 00:58:03 -05:00
Jarvis
a00325da0e feat(forge): add registerForgeCommand for mosaic forge CLI surface
Adds mosaic forge run|status|resume|personas list subcommands to
@mosaicstack/forge, wires registerForgeCommand into the root mosaic CLI,
and ships a smoke test asserting command structure. Ref CU-05-01
cli-unification-20260404.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 00:58:03 -05:00
4ebce3422d feat(log): mosaic log CLI surface (#407)
Some checks failed
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/publish Pipeline failed
2026-04-05 05:57:22 +00:00
751e0ee330 feat(storage): mosaic storage CLI surface (#405)
Some checks failed
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/publish Pipeline failed
2026-04-05 05:48:13 +00:00
54b2920ef3 feat(memory): mosaic memory CLI surface (#406)
Some checks failed
ci/woodpecker/push/ci Pipeline failed
ci/woodpecker/push/publish Pipeline failed
2026-04-05 05:44:06 +00:00
5917016509 feat(mosaic): gateway token recovery via BetterAuth cookie (#411)
Some checks are pending
ci/woodpecker/push/ci Pipeline is pending
ci/woodpecker/push/publish Pipeline is pending
2026-04-05 05:43:49 +00:00
7b4f1d249d feat(mosaic): top-level mosaic config command (#408)
Some checks failed
ci/woodpecker/push/publish Pipeline failed
ci/woodpecker/push/ci Pipeline failed
2026-04-05 05:37:05 +00:00
5425f9268e feat(queue): mosaic queue CLI surface (#404)
Some checks failed
ci/woodpecker/push/publish Pipeline failed
ci/woodpecker/push/ci Pipeline failed
2026-04-05 05:27:59 +00:00
febd866098 feat(brain): mosaic brain CLI surface (#403)
Some checks failed
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/publish Pipeline failed
2026-04-05 05:20:44 +00:00
2446593fff feat(mosaic): alphabetize and group mosaic --help output (#402)
Some checks failed
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/publish Pipeline failed
2026-04-05 05:12:32 +00:00
651426cf2e docs(plan): gateway admin token recovery flow (#401)
Some checks failed
ci/woodpecker/push/publish Pipeline failed
ci/woodpecker/push/ci Pipeline failed
2026-04-05 05:11:33 +00:00
cf46f6e0ae docs: capture planning decisions + session 1 handoff (#400)
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/publish Pipeline was successful
2026-04-05 04:57:00 +00:00
6f15a84ccf docs: archive stale mission, scaffold CLI unification mission (#399)
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/publish Pipeline was successful
2026-04-05 04:47:54 +00:00
c39433c361 chore: remove legacy @mosaicstack/cli package (#398)
Some checks failed
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/publish Pipeline failed
2026-04-05 04:39:46 +00:00
257796ce87 Merge pull request 'chore: bump @mosaicstack/mosaic to 0.0.21 for republish' (#397) from chore/bump-mosaic-0.0.21 into main
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/publish Pipeline was successful
2026-04-05 04:12:05 +00:00
Jarvis
2357602f50 chore: bump @mosaicstack/mosaic to 0.0.21 for publish
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/pr/ci Pipeline was successful
2026-04-04 23:09:52 -05:00
1230f6b984 ci: fail publish pipeline loudly on registry/auth/network errors (#396)
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/publish Pipeline was successful
2026-04-05 03:58:35 +00:00
14b775f1b9 Merge pull request 'fix: populate KNOWN_PACKAGES for mosaic update command' (#395) from fix/populate-known-packages-list into main
Some checks failed
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/publish Pipeline failed
Reviewed-on: mosaicstack/mosaic-stack#395
2026-04-05 03:52:57 +00:00
Jarvis
c7691d9807 fix: populate KNOWN_PACKAGES with all workspace packages for 'mosaic update'
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/pr/ci Pipeline was successful
- Remove @mosaicstack/cli (absorbed into @mosaicstack/mosaic)
- Add all 21 remaining workspace packages so the multi-package
  update checker actually covers every published package
2026-04-04 22:49:45 -05:00
9a53d55678 Merge pull request 'fix: update Gitea org references from mosaic/ to mosaicstack/' (#394) from fix/gitea-org-rename into main
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/publish Pipeline was successful
Reviewed-on: mosaicstack/mosaic-stack#394
2026-04-05 03:35:11 +00:00
Jarvis
31008ef7ff fix: update Gitea org references from mosaic/ to mosaicstack/
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/pr/ci Pipeline was successful
- Update all package.json repo URLs (mosaic/mosaic-stack → mosaicstack/mosaic-stack)
- Update npm registry URLs (/api/packages/mosaic/npm → /api/packages/mosaicstack/npm)
- Update woodpecker publish destinations
- Update tools/install.sh registry and repo base URLs
2026-04-04 22:31:20 -05:00
621ab260c0 fix(mosaic): resumable gateway install + prominent admin token (#393)
Some checks failed
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/publish Pipeline was successful
ci/woodpecker/manual/publish Pipeline failed
ci/woodpecker/manual/ci Pipeline failed
2026-04-05 03:19:07 +00:00
2b1840214e Merge pull request 'fix: rename @mosaic/* packages to @mosaicstack/*' (#392) from fix/rename-mosaic-scope-391 into main
Some checks failed
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/publish Pipeline failed
2026-04-05 03:11:55 +00:00
Jarvis
5cfccc2ead fix(mosaic): remove unused hasUpdate variable in formatAllPackagesTable
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/pr/ci Pipeline was successful
Fixes lint error:
@typescript-eslint/no-unused-vars on hasUpdate
2026-04-04 22:01:01 -05:00
Jarvis
774b76447d fix: rename all packages from @mosaic/* to @mosaicstack/*
Some checks failed
ci/woodpecker/pr/ci Pipeline failed
ci/woodpecker/push/ci Pipeline failed
- Updated all package.json name fields and dependency references
- Updated all TypeScript/JavaScript imports
- Updated .woodpecker/publish.yml filters and registry paths
- Updated tools/install.sh scope default
- Updated .npmrc registry paths (worktree + host)
- Enhanced update-checker.ts with checkForAllUpdates() multi-package support
- Updated CLI update command to show table of all packages
- Added KNOWN_PACKAGES, formatAllPackagesTable, getInstallAllCommand
- Marked checkForUpdate() with @deprecated JSDoc

Closes #391
2026-04-04 21:43:23 -05:00
80994bdc8e fix(packages): bump db/memory/queue for PGlite + adapter factories (#389)
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/publish Pipeline was successful
2026-04-05 02:20:23 +00:00
2e31626f87 fix: simplify updater to @mosaic/mosaic only, add explicit tea repo/login flags (#388)
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/publish Pipeline was successful
2026-04-05 02:09:23 +00:00
279 changed files with 7775 additions and 7581 deletions

2
.npmrc
View File

@@ -1 +1 @@
@mosaic:registry=https://git.mosaicstack.dev/api/packages/mosaic/npm/ @mosaicstack:registry=https://git.mosaicstack.dev/api/packages/mosaicstack/npm/

View File

@@ -59,7 +59,7 @@ steps:
sleep 1 sleep 1
done done
# Run migrations (DATABASE_URL is set in environment above) # Run migrations (DATABASE_URL is set in environment above)
- pnpm --filter @mosaic/db run db:migrate - pnpm --filter @mosaicstack/db run db:migrate
# Run all tests # Run all tests
- pnpm test - pnpm test
depends_on: depends_on:

View File

@@ -33,15 +33,44 @@ steps:
- *enable_pnpm - *enable_pnpm
# Configure auth for Gitea npm registry # Configure auth for Gitea npm registry
- | - |
echo "//git.mosaicstack.dev/api/packages/mosaic/npm/:_authToken=$NPM_TOKEN" > ~/.npmrc echo "//git.mosaicstack.dev/api/packages/mosaicstack/npm/:_authToken=$NPM_TOKEN" > ~/.npmrc
echo "@mosaic:registry=https://git.mosaicstack.dev/api/packages/mosaic/npm/" >> ~/.npmrc echo "@mosaicstack:registry=https://git.mosaicstack.dev/api/packages/mosaicstack/npm/" >> ~/.npmrc
# Publish non-private packages to Gitea (--no-git-checks skips dirty/branch checks in CI) # Publish non-private packages to Gitea.
# --filter excludes web (private) #
- > # The only publish failure we tolerate is "version already exists" —
pnpm --filter "@mosaic/*" # that legitimately happens when only some packages were bumped in
--filter "!@mosaic/web" # the merge. Any other failure (registry 404, auth error, network
publish --no-git-checks --access public # error) MUST fail the pipeline loudly: the previous
|| echo "[publish] Some packages may already exist at this version — continuing" # `|| echo "... continuing"` fallback silently hid a 404 from the
# Gitea org rename and caused every @mosaicstack/* publish to fall
# on the floor while CI still reported green.
- |
# Portable sh (Alpine ash) — avoid bashisms like PIPESTATUS.
set +e
pnpm --filter "@mosaicstack/*" --filter "!@mosaicstack/web" publish --no-git-checks --access public >/tmp/publish.log 2>&1
EXIT=$?
set -e
cat /tmp/publish.log
if [ "$EXIT" -eq 0 ]; then
echo "[publish] all packages published successfully"
exit 0
fi
# Hard registry / auth / network errors → fatal. Match npm's own
# error lines specifically to avoid false positives on arbitrary
# log text that happens to contain "E404" etc.
if grep -qE "npm (error|ERR!) code (E404|E401|ENEEDAUTH|ECONNREFUSED|ETIMEDOUT|ENOTFOUND)" /tmp/publish.log; then
echo "[publish] FATAL: registry/auth/network error detected — failing pipeline" >&2
exit 1
fi
# Only tolerate the explicit "version already published" case.
# npm returns this as E403 with body "You cannot publish over..."
# or EPUBLISHCONFLICT depending on version.
if grep -qE "EPUBLISHCONFLICT|You cannot publish over|previously published" /tmp/publish.log; then
echo "[publish] some packages already at this version — continuing (non-fatal)"
exit 0
fi
echo "[publish] FATAL: publish failed with unrecognized error — failing pipeline" >&2
exit 1
depends_on: depends_on:
- build - build
@@ -74,12 +103,12 @@ steps:
- mkdir -p /kaniko/.docker - mkdir -p /kaniko/.docker
- echo "{\"auths\":{\"git.mosaicstack.dev\":{\"username\":\"$REGISTRY_USER\",\"password\":\"$REGISTRY_PASS\"}}}" > /kaniko/.docker/config.json - echo "{\"auths\":{\"git.mosaicstack.dev\":{\"username\":\"$REGISTRY_USER\",\"password\":\"$REGISTRY_PASS\"}}}" > /kaniko/.docker/config.json
- | - |
DESTINATIONS="--destination git.mosaicstack.dev/mosaic/mosaic-stack/gateway:sha-${CI_COMMIT_SHA:0:7}" DESTINATIONS="--destination git.mosaicstack.dev/mosaicstack/mosaic-stack/gateway:sha-${CI_COMMIT_SHA:0:7}"
if [ "$CI_COMMIT_BRANCH" = "main" ]; then if [ "$CI_COMMIT_BRANCH" = "main" ]; then
DESTINATIONS="$DESTINATIONS --destination git.mosaicstack.dev/mosaic/mosaic-stack/gateway:latest" DESTINATIONS="$DESTINATIONS --destination git.mosaicstack.dev/mosaicstack/mosaic-stack/gateway:latest"
fi fi
if [ -n "$CI_COMMIT_TAG" ]; then if [ -n "$CI_COMMIT_TAG" ]; then
DESTINATIONS="$DESTINATIONS --destination git.mosaicstack.dev/mosaic/mosaic-stack/gateway:$CI_COMMIT_TAG" DESTINATIONS="$DESTINATIONS --destination git.mosaicstack.dev/mosaicstack/mosaic-stack/gateway:$CI_COMMIT_TAG"
fi fi
/kaniko/executor --context . --dockerfile docker/gateway.Dockerfile $DESTINATIONS /kaniko/executor --context . --dockerfile docker/gateway.Dockerfile $DESTINATIONS
depends_on: depends_on:
@@ -99,12 +128,12 @@ steps:
- mkdir -p /kaniko/.docker - mkdir -p /kaniko/.docker
- echo "{\"auths\":{\"git.mosaicstack.dev\":{\"username\":\"$REGISTRY_USER\",\"password\":\"$REGISTRY_PASS\"}}}" > /kaniko/.docker/config.json - echo "{\"auths\":{\"git.mosaicstack.dev\":{\"username\":\"$REGISTRY_USER\",\"password\":\"$REGISTRY_PASS\"}}}" > /kaniko/.docker/config.json
- | - |
DESTINATIONS="--destination git.mosaicstack.dev/mosaic/mosaic-stack/web:sha-${CI_COMMIT_SHA:0:7}" DESTINATIONS="--destination git.mosaicstack.dev/mosaicstack/mosaic-stack/web:sha-${CI_COMMIT_SHA:0:7}"
if [ "$CI_COMMIT_BRANCH" = "main" ]; then if [ "$CI_COMMIT_BRANCH" = "main" ]; then
DESTINATIONS="$DESTINATIONS --destination git.mosaicstack.dev/mosaic/mosaic-stack/web:latest" DESTINATIONS="$DESTINATIONS --destination git.mosaicstack.dev/mosaicstack/mosaic-stack/web:latest"
fi fi
if [ -n "$CI_COMMIT_TAG" ]; then if [ -n "$CI_COMMIT_TAG" ]; then
DESTINATIONS="$DESTINATIONS --destination git.mosaicstack.dev/mosaic/mosaic-stack/web:$CI_COMMIT_TAG" DESTINATIONS="$DESTINATIONS --destination git.mosaicstack.dev/mosaicstack/mosaic-stack/web:$CI_COMMIT_TAG"
fi fi
/kaniko/executor --context . --dockerfile docker/web.Dockerfile $DESTINATIONS /kaniko/executor --context . --dockerfile docker/web.Dockerfile $DESTINATIONS
depends_on: depends_on:

View File

@@ -21,11 +21,11 @@ Mosaic Stack is a self-hosted, multi-user AI agent platform. TypeScript monorepo
| `apps/web` | Next.js dashboard | React 19, Tailwind | | `apps/web` | Next.js dashboard | React 19, Tailwind |
| `packages/types` | Shared TypeScript contracts | class-validator | | `packages/types` | Shared TypeScript contracts | class-validator |
| `packages/db` | Drizzle ORM schema + migrations | drizzle-orm, postgres | | `packages/db` | Drizzle ORM schema + migrations | drizzle-orm, postgres |
| `packages/auth` | BetterAuth configuration | better-auth, @mosaic/db | | `packages/auth` | BetterAuth configuration | better-auth, @mosaicstack/db |
| `packages/brain` | Data layer (PG-backed) | @mosaic/db | | `packages/brain` | Data layer (PG-backed) | @mosaicstack/db |
| `packages/queue` | Valkey task queue + MCP | ioredis | | `packages/queue` | Valkey task queue + MCP | ioredis |
| `packages/coord` | Mission coordination | @mosaic/queue | | `packages/coord` | Mission coordination | @mosaicstack/queue |
| `packages/cli` | Unified CLI + Pi TUI | Ink, Pi SDK | | `packages/mosaic` | Unified `mosaic` CLI + TUI | Ink, Pi SDK, commander |
| `plugins/discord` | Discord channel plugin | discord.js | | `plugins/discord` | Discord channel plugin | discord.js |
| `plugins/telegram` | Telegram channel plugin | Telegraf | | `plugins/telegram` | Telegram channel plugin | Telegraf |
@@ -33,9 +33,9 @@ Mosaic Stack is a self-hosted, multi-user AI agent platform. TypeScript monorepo
1. Gateway is the single API surface — all clients connect through it 1. Gateway is the single API surface — all clients connect through it
2. Pi SDK is ESM-only — gateway and CLI must use ESM 2. Pi SDK is ESM-only — gateway and CLI must use ESM
3. Socket.IO typed events defined in `@mosaic/types` enforce compile-time contracts 3. Socket.IO typed events defined in `@mosaicstack/types` enforce compile-time contracts
4. OTEL auto-instrumentation loads before NestJS bootstrap 4. OTEL auto-instrumentation loads before NestJS bootstrap
5. BetterAuth manages auth tables; schema defined in `@mosaic/db` 5. BetterAuth manages auth tables; schema defined in `@mosaicstack/db`
6. Docker Compose provides PG (5433), Valkey (6380), OTEL Collector (4317/4318), Jaeger (16686) 6. Docker Compose provides PG (5433), Valkey (6380), OTEL Collector (4317/4318), Jaeger (16686)
7. Explicit `@Inject()` decorators required in NestJS (tsx/esbuild doesn't emit decorator metadata) 7. Explicit `@Inject()` decorators required in NestJS (tsx/esbuild doesn't emit decorator metadata)

View File

@@ -10,7 +10,7 @@ Self-hosted, multi-user AI agent platform. TypeScript monorepo.
- **Web**: Next.js 16 + React 19 (`apps/web`) - **Web**: Next.js 16 + React 19 (`apps/web`)
- **ORM**: Drizzle ORM + PostgreSQL 17 + pgvector (`packages/db`) - **ORM**: Drizzle ORM + PostgreSQL 17 + pgvector (`packages/db`)
- **Auth**: BetterAuth (`packages/auth`) - **Auth**: BetterAuth (`packages/auth`)
- **Agent**: Pi SDK (`packages/agent`, `packages/cli`) - **Agent**: Pi SDK (`packages/agent`, `packages/mosaic`)
- **Queue**: Valkey 8 (`packages/queue`) - **Queue**: Valkey 8 (`packages/queue`)
- **Build**: pnpm workspaces + Turborepo - **Build**: pnpm workspaces + Turborepo
- **CI**: Woodpecker CI - **CI**: Woodpecker CI
@@ -26,13 +26,13 @@ pnpm test # Vitest (all packages)
pnpm build # Build all packages pnpm build # Build all packages
# Database # Database
pnpm --filter @mosaic/db db:push # Push schema to PG (dev) pnpm --filter @mosaicstack/db db:push # Push schema to PG (dev)
pnpm --filter @mosaic/db db:generate # Generate migrations pnpm --filter @mosaicstack/db db:generate # Generate migrations
pnpm --filter @mosaic/db db:migrate # Run migrations pnpm --filter @mosaicstack/db db:migrate # Run migrations
# Dev # Dev
docker compose up -d # Start PG, Valkey, OTEL, Jaeger docker compose up -d # Start PG, Valkey, OTEL, Jaeger
pnpm --filter @mosaic/gateway exec tsx src/main.ts # Start gateway pnpm --filter @mosaicstack/gateway exec tsx src/main.ts # Start gateway
``` ```
## Conventions ## Conventions

144
README.md
View File

@@ -7,26 +7,33 @@ Mosaic gives you a unified launcher for Claude Code, Codex, OpenCode, and Pi —
## Quick Install ## Quick Install
```bash ```bash
bash <(curl -fsSL https://git.mosaicstack.dev/mosaic/mosaic-stack/raw/branch/main/tools/install.sh) bash <(curl -fsSL https://git.mosaicstack.dev/mosaicstack/mosaic-stack/raw/branch/main/tools/install.sh)
```
The installer auto-launches the setup wizard, which walks you through gateway install and verification. Flags for non-interactive use:
```bash
bash <(curl -fsSL …) --yes # Accept all defaults
bash <(curl -fsSL …) --yes --no-auto-launch # Install only, skip wizard
``` ```
This installs both components: This installs both components:
| Component | What | Where | | Component | What | Where |
| --------------- | ----------------------------------------------------- | -------------------- | | ----------------------- | ---------------------------------------------------------------- | -------------------- |
| **Framework** | Bash launcher, guides, runtime configs, tools, skills | `~/.config/mosaic/` | | **Framework** | Bash launcher, guides, runtime configs, tools, skills | `~/.config/mosaic/` |
| **@mosaic/cli** | TUI, gateway client, wizard, auto-updater | `~/.npm-global/bin/` | | **@mosaicstack/mosaic** | Unified `mosaic` CLI — TUI, gateway client, wizard, auto-updater | `~/.npm-global/bin/` |
After install, set up your agent identity: After install, the wizard runs automatically or you can invoke it manually:
```bash ```bash
mosaic init # Interactive wizard mosaic wizard # Full guided setup (gateway install → verify)
``` ```
### Requirements ### Requirements
- Node.js ≥ 20 - Node.js ≥ 20
- npm (for global @mosaic/cli install) - npm (for global @mosaicstack/mosaic install)
- One or more runtimes: [Claude Code](https://docs.anthropic.com/en/docs/claude-code), [Codex](https://github.com/openai/codex), [OpenCode](https://opencode.ai), or [Pi](https://github.com/mariozechner/pi-coding-agent) - One or more runtimes: [Claude Code](https://docs.anthropic.com/en/docs/claude-code), [Codex](https://github.com/openai/codex), [OpenCode](https://opencode.ai), or [Pi](https://github.com/mariozechner/pi-coding-agent)
## Usage ## Usage
@@ -49,10 +56,32 @@ The launcher verifies your config, checks for `SOUL.md`, injects your `AGENTS.md
```bash ```bash
mosaic tui # Interactive TUI connected to the gateway mosaic tui # Interactive TUI connected to the gateway
mosaic login # Authenticate with a gateway instance mosaic gateway login # Authenticate with a gateway instance
mosaic sessions list # List active agent sessions mosaic sessions list # List active agent sessions
``` ```
### Gateway Management
```bash
mosaic gateway install # Install and configure the gateway service
mosaic gateway verify # Post-install health check
mosaic gateway login # Authenticate and store a session token
mosaic gateway config rotate-token # Rotate your API token
mosaic gateway config recover-token # Recover a token via BetterAuth cookie
```
If you already have a gateway account but no token, use `mosaic gateway config recover-token` to retrieve one without recreating your account.
### Configuration
```bash
mosaic config show # Print full config as JSON
mosaic config get <key> # Read a specific key
mosaic config set <key> <val># Write a key
mosaic config edit # Open config in $EDITOR
mosaic config path # Print config file path
```
### Management ### Management
```bash ```bash
@@ -65,6 +94,80 @@ mosaic coord init # Initialize a new orchestration mission
mosaic prdy init # Create a PRD via guided session mosaic prdy init # Create a PRD via guided session
``` ```
### Sub-package Commands
Each Mosaic sub-package exposes its API surface through the unified CLI:
```bash
# User management
mosaic auth users list
mosaic auth users create
mosaic auth sso
# Agent brain (projects, missions, tasks)
mosaic brain projects
mosaic brain missions
mosaic brain tasks
mosaic brain conversations
# Agent forge pipeline
mosaic forge run
mosaic forge status
mosaic forge resume
mosaic forge personas
# Structured logging
mosaic log tail
mosaic log search
mosaic log export
mosaic log level
# MACP protocol
mosaic macp tasks
mosaic macp submit
mosaic macp gate
mosaic macp events
# Agent memory
mosaic memory search
mosaic memory stats
mosaic memory insights
mosaic memory preferences
# Task queue (Valkey)
mosaic queue list
mosaic queue stats
mosaic queue pause
mosaic queue resume
mosaic queue jobs
mosaic queue drain
# Object storage
mosaic storage status
mosaic storage tier
mosaic storage export
mosaic storage import
mosaic storage migrate
```
### Telemetry
```bash
# Local observability (OTEL / Jaeger)
mosaic telemetry local status
mosaic telemetry local tail
mosaic telemetry local jaeger
# Remote telemetry (dry-run by default)
mosaic telemetry status
mosaic telemetry opt-in
mosaic telemetry opt-out
mosaic telemetry test
mosaic telemetry upload # Dry-run unless opted in
```
Consent state is persisted in config. Remote upload is a no-op until you run `mosaic telemetry opt-in`.
## Development ## Development
### Prerequisites ### Prerequisites
@@ -76,7 +179,7 @@ mosaic prdy init # Create a PRD via guided session
### Setup ### Setup
```bash ```bash
git clone git@git.mosaicstack.dev:mosaic/mosaic-stack.git git clone git@git.mosaicstack.dev:mosaicstack/mosaic-stack.git
cd mosaic-stack cd mosaic-stack
# Start infrastructure (Postgres, Valkey, Jaeger) # Start infrastructure (Postgres, Valkey, Jaeger)
@@ -86,7 +189,7 @@ docker compose up -d
pnpm install pnpm install
# Run migrations # Run migrations
pnpm --filter @mosaic/db run db:migrate pnpm --filter @mosaicstack/db run db:migrate
# Start all services in dev mode # Start all services in dev mode
pnpm dev pnpm dev
@@ -131,8 +234,7 @@ mosaic-stack/
│ ├── gateway/ NestJS API + WebSocket hub (Fastify, Socket.IO, OTEL) │ ├── gateway/ NestJS API + WebSocket hub (Fastify, Socket.IO, OTEL)
│ └── web/ Next.js dashboard (React 19, Tailwind) │ └── web/ Next.js dashboard (React 19, Tailwind)
├── packages/ ├── packages/
│ ├── cli/ Mosaic CLI — TUI, gateway client, wizard │ ├── mosaic/ Unified CLI — TUI, gateway client, wizard, sub-package commands
│ ├── mosaic/ Framework — wizard, runtime detection, update checker
│ ├── types/ Shared TypeScript contracts (Socket.IO typed events) │ ├── types/ Shared TypeScript contracts (Socket.IO typed events)
│ ├── db/ Drizzle ORM schema + migrations (pgvector) │ ├── db/ Drizzle ORM schema + migrations (pgvector)
│ ├── auth/ BetterAuth configuration │ ├── auth/ BetterAuth configuration
@@ -153,7 +255,7 @@ mosaic-stack/
│ ├── macp/ OpenClaw MACP runtime plugin │ ├── macp/ OpenClaw MACP runtime plugin
│ └── mosaic-framework/ OpenClaw framework injection plugin │ └── mosaic-framework/ OpenClaw framework injection plugin
├── tools/ ├── tools/
│ └── install.sh Unified installer (framework + npm CLI) │ └── install.sh Unified installer (framework + npm CLI, --yes / --no-auto-launch)
├── scripts/agent/ Agent session lifecycle scripts ├── scripts/agent/ Agent session lifecycle scripts
├── docker-compose.yml Dev infrastructure ├── docker-compose.yml Dev infrastructure
└── .woodpecker/ CI pipeline configs └── .woodpecker/ CI pipeline configs
@@ -163,7 +265,7 @@ mosaic-stack/
- **Gateway is the single API surface** — all clients (TUI, web, Discord, Telegram) connect through it - **Gateway is the single API surface** — all clients (TUI, web, Discord, Telegram) connect through it
- **ESM everywhere** — `"type": "module"`, `.js` extensions in imports, NodeNext resolution - **ESM everywhere** — `"type": "module"`, `.js` extensions in imports, NodeNext resolution
- **Socket.IO typed events** — defined in `@mosaic/types`, enforced at compile time - **Socket.IO typed events** — defined in `@mosaicstack/types`, enforced at compile time
- **OTEL auto-instrumentation** — loads before NestJS bootstrap - **OTEL auto-instrumentation** — loads before NestJS bootstrap
- **Explicit `@Inject()` decorators** — required since tsx/esbuild doesn't emit decorator metadata - **Explicit `@Inject()` decorators** — required since tsx/esbuild doesn't emit decorator metadata
@@ -200,7 +302,7 @@ Each stage has a dispatch mode (`exec` for research/review, `yolo` for coding),
Run the installer again — it handles upgrades automatically: Run the installer again — it handles upgrades automatically:
```bash ```bash
bash <(curl -fsSL https://git.mosaicstack.dev/mosaic/mosaic-stack/raw/branch/main/tools/install.sh) bash <(curl -fsSL https://git.mosaicstack.dev/mosaicstack/mosaic-stack/raw/branch/main/tools/install.sh)
``` ```
Or use the CLI: Or use the CLI:
@@ -215,10 +317,12 @@ The CLI also performs a background update check on every invocation (cached for
### Installer Flags ### Installer Flags
```bash ```bash
bash tools/install.sh --check # Version check only bash tools/install.sh --check # Version check only
bash tools/install.sh --framework # Framework only (skip npm CLI) bash tools/install.sh --framework # Framework only (skip npm CLI)
bash tools/install.sh --cli # npm CLI only (skip framework) bash tools/install.sh --cli # npm CLI only (skip framework)
bash tools/install.sh --ref v1.0 # Install from a specific git ref bash tools/install.sh --ref v1.0 # Install from a specific git ref
bash tools/install.sh --yes # Non-interactive, accept all defaults
bash tools/install.sh --no-auto-launch # Skip auto-launch of wizard
``` ```
## Contributing ## Contributing

View File

@@ -1,9 +1,9 @@
{ {
"name": "@mosaic/gateway", "name": "@mosaicstack/gateway",
"version": "0.0.5", "version": "0.0.6",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://git.mosaicstack.dev/mosaic/mosaic-stack.git", "url": "https://git.mosaicstack.dev/mosaicstack/mosaic-stack.git",
"directory": "apps/gateway" "directory": "apps/gateway"
}, },
"type": "module", "type": "module",
@@ -15,7 +15,7 @@
"dist" "dist"
], ],
"publishConfig": { "publishConfig": {
"registry": "https://git.mosaicstack.dev/api/packages/mosaic/npm/", "registry": "https://git.mosaicstack.dev/api/packages/mosaicstack/npm/",
"access": "public" "access": "public"
}, },
"scripts": { "scripts": {
@@ -31,18 +31,18 @@
"@mariozechner/pi-ai": "^0.65.0", "@mariozechner/pi-ai": "^0.65.0",
"@mariozechner/pi-coding-agent": "^0.65.0", "@mariozechner/pi-coding-agent": "^0.65.0",
"@modelcontextprotocol/sdk": "^1.27.1", "@modelcontextprotocol/sdk": "^1.27.1",
"@mosaic/auth": "workspace:^", "@mosaicstack/auth": "workspace:^",
"@mosaic/brain": "workspace:^", "@mosaicstack/brain": "workspace:^",
"@mosaic/config": "workspace:^", "@mosaicstack/config": "workspace:^",
"@mosaic/coord": "workspace:^", "@mosaicstack/coord": "workspace:^",
"@mosaic/db": "workspace:^", "@mosaicstack/db": "workspace:^",
"@mosaic/discord-plugin": "workspace:^", "@mosaicstack/discord-plugin": "workspace:^",
"@mosaic/log": "workspace:^", "@mosaicstack/log": "workspace:^",
"@mosaic/memory": "workspace:^", "@mosaicstack/memory": "workspace:^",
"@mosaic/queue": "workspace:^", "@mosaicstack/queue": "workspace:^",
"@mosaic/storage": "workspace:^", "@mosaicstack/storage": "workspace:^",
"@mosaic/telegram-plugin": "workspace:^", "@mosaicstack/telegram-plugin": "workspace:^",
"@mosaic/types": "workspace:^", "@mosaicstack/types": "workspace:^",
"@nestjs/common": "^11.0.0", "@nestjs/common": "^11.0.0",
"@nestjs/core": "^11.0.0", "@nestjs/core": "^11.0.0",
"@nestjs/platform-fastify": "^11.0.0", "@nestjs/platform-fastify": "^11.0.0",

View File

@@ -12,7 +12,7 @@ import { BadRequestException, NotFoundException } from '@nestjs/common';
import { describe, expect, it, vi, beforeEach } from 'vitest'; import { describe, expect, it, vi, beforeEach } from 'vitest';
import type { ConversationHistoryMessage } from '../agent/agent.service.js'; import type { ConversationHistoryMessage } from '../agent/agent.service.js';
import { ConversationsController } from '../conversations/conversations.controller.js'; import { ConversationsController } from '../conversations/conversations.controller.js';
import type { Message } from '@mosaic/brain'; import type { Message } from '@mosaicstack/brain';
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Shared test data // Shared test data

View File

@@ -18,13 +18,13 @@
*/ */
import { afterAll, beforeAll, beforeEach, describe, expect, it } from 'vitest'; import { afterAll, beforeAll, beforeEach, describe, expect, it } from 'vitest';
import { createDb } from '@mosaic/db'; import { createDb } from '@mosaicstack/db';
import { createConversationsRepo } from '@mosaic/brain'; import { createConversationsRepo } from '@mosaicstack/brain';
import { createAgentsRepo } from '@mosaic/brain'; import { createAgentsRepo } from '@mosaicstack/brain';
import { createPreferencesRepo, createInsightsRepo } from '@mosaic/memory'; import { createPreferencesRepo, createInsightsRepo } from '@mosaicstack/memory';
import { users, conversations, messages, agents, preferences, insights } from '@mosaic/db'; import { users, conversations, messages, agents, preferences, insights } from '@mosaicstack/db';
import { eq } from '@mosaic/db'; import { eq } from '@mosaicstack/db';
import type { DbHandle } from '@mosaic/db'; import type { DbHandle } from '@mosaicstack/db';
// ─── Fixed IDs so the afterAll cleanup is deterministic ────────────────────── // ─── Fixed IDs so the afterAll cleanup is deterministic ──────────────────────

View File

@@ -1,6 +1,6 @@
import { Controller, Get, Inject, UseGuards } from '@nestjs/common'; import { Controller, Get, Inject, UseGuards } from '@nestjs/common';
import { sql, type Db } from '@mosaic/db'; import { sql, type Db } from '@mosaicstack/db';
import { createQueue } from '@mosaic/queue'; import { createQueue } from '@mosaicstack/queue';
import { DB } from '../database/database.module.js'; import { DB } from '../database/database.module.js';
import { AgentService } from '../agent/agent.service.js'; import { AgentService } from '../agent/agent.service.js';
import { ProviderService } from '../agent/provider.service.js'; import { ProviderService } from '../agent/provider.service.js';

View File

@@ -11,7 +11,7 @@ import {
UseGuards, UseGuards,
} from '@nestjs/common'; } from '@nestjs/common';
import { randomBytes, createHash } from 'node:crypto'; import { randomBytes, createHash } from 'node:crypto';
import { eq, type Db, adminTokens } from '@mosaic/db'; import { eq, type Db, adminTokens } from '@mosaicstack/db';
import { v4 as uuid } from 'uuid'; import { v4 as uuid } from 'uuid';
import { DB } from '../database/database.module.js'; import { DB } from '../database/database.module.js';
import { AdminGuard } from './admin.guard.js'; import { AdminGuard } from './admin.guard.js';

View File

@@ -13,8 +13,8 @@ import {
Post, Post,
UseGuards, UseGuards,
} from '@nestjs/common'; } from '@nestjs/common';
import { eq, type Db, users as usersTable } from '@mosaic/db'; import { eq, type Db, users as usersTable } from '@mosaicstack/db';
import type { Auth } from '@mosaic/auth'; import type { Auth } from '@mosaicstack/auth';
import { AUTH } from '../auth/auth.tokens.js'; import { AUTH } from '../auth/auth.tokens.js';
import { DB } from '../database/database.module.js'; import { DB } from '../database/database.module.js';
import { AdminGuard } from './admin.guard.js'; import { AdminGuard } from './admin.guard.js';

View File

@@ -8,9 +8,9 @@ import {
} from '@nestjs/common'; } from '@nestjs/common';
import { createHash } from 'node:crypto'; import { createHash } from 'node:crypto';
import { fromNodeHeaders } from 'better-auth/node'; import { fromNodeHeaders } from 'better-auth/node';
import type { Auth } from '@mosaic/auth'; import type { Auth } from '@mosaicstack/auth';
import type { Db } from '@mosaic/db'; import type { Db } from '@mosaicstack/db';
import { eq, adminTokens, users as usersTable } from '@mosaic/db'; import { eq, adminTokens, users as usersTable } from '@mosaicstack/db';
import type { FastifyRequest } from 'fastify'; import type { FastifyRequest } from 'fastify';
import { AUTH } from '../auth/auth.tokens.js'; import { AUTH } from '../auth/auth.tokens.js';
import { DB } from '../database/database.module.js'; import { DB } from '../database/database.module.js';

View File

@@ -8,8 +8,8 @@ import {
Post, Post,
} from '@nestjs/common'; } from '@nestjs/common';
import { randomBytes, createHash } from 'node:crypto'; import { randomBytes, createHash } from 'node:crypto';
import { count, eq, type Db, users as usersTable, adminTokens } from '@mosaic/db'; import { count, eq, type Db, users as usersTable, adminTokens } from '@mosaicstack/db';
import type { Auth } from '@mosaic/auth'; import type { Auth } from '@mosaicstack/auth';
import { v4 as uuid } from 'uuid'; import { v4 as uuid } from 'uuid';
import { AUTH } from '../auth/auth.tokens.js'; import { AUTH } from '../auth/auth.tokens.js';
import { DB } from '../database/database.module.js'; import { DB } from '../database/database.module.js';

View File

@@ -1,6 +1,6 @@
import { describe, it, expect, beforeEach, vi } from 'vitest'; import { describe, it, expect, beforeEach, vi } from 'vitest';
import { RoutingService } from '../routing.service.js'; import { RoutingService } from '../routing.service.js';
import type { ModelInfo } from '@mosaic/types'; import type { ModelInfo } from '@mosaicstack/types';
const mockModels: ModelInfo[] = [ const mockModels: ModelInfo[] = [
{ {

View File

@@ -7,7 +7,7 @@ import type {
IProviderAdapter, IProviderAdapter,
ModelInfo, ModelInfo,
ProviderHealth, ProviderHealth,
} from '@mosaic/types'; } from '@mosaicstack/types';
/** /**
* Anthropic provider adapter. * Anthropic provider adapter.

View File

@@ -6,7 +6,7 @@ import type {
IProviderAdapter, IProviderAdapter,
ModelInfo, ModelInfo,
ProviderHealth, ProviderHealth,
} from '@mosaic/types'; } from '@mosaicstack/types';
/** Embedding models that Ollama ships with out of the box */ /** Embedding models that Ollama ships with out of the box */
const OLLAMA_EMBEDDING_MODELS: ReadonlyArray<{ const OLLAMA_EMBEDDING_MODELS: ReadonlyArray<{

View File

@@ -7,7 +7,7 @@ import type {
IProviderAdapter, IProviderAdapter,
ModelInfo, ModelInfo,
ProviderHealth, ProviderHealth,
} from '@mosaic/types'; } from '@mosaicstack/types';
/** /**
* OpenAI provider adapter. * OpenAI provider adapter.

View File

@@ -6,7 +6,7 @@ import type {
IProviderAdapter, IProviderAdapter,
ModelInfo, ModelInfo,
ProviderHealth, ProviderHealth,
} from '@mosaic/types'; } from '@mosaicstack/types';
const OPENROUTER_BASE_URL = 'https://openrouter.ai/api/v1'; const OPENROUTER_BASE_URL = 'https://openrouter.ai/api/v1';

View File

@@ -6,7 +6,7 @@ import type {
IProviderAdapter, IProviderAdapter,
ModelInfo, ModelInfo,
ProviderHealth, ProviderHealth,
} from '@mosaic/types'; } from '@mosaicstack/types';
import { getModelCapability } from '../model-capabilities.js'; import { getModelCapability } from '../model-capabilities.js';
/** /**

View File

@@ -13,7 +13,7 @@ import {
Post, Post,
UseGuards, UseGuards,
} from '@nestjs/common'; } from '@nestjs/common';
import type { Brain } from '@mosaic/brain'; import type { Brain } from '@mosaicstack/brain';
import { BRAIN } from '../brain/brain.tokens.js'; import { BRAIN } from '../brain/brain.tokens.js';
import { AuthGuard } from '../auth/auth.guard.js'; import { AuthGuard } from '../auth/auth.guard.js';
import { CurrentUser } from '../auth/current-user.decorator.js'; import { CurrentUser } from '../auth/current-user.decorator.js';

View File

@@ -7,8 +7,8 @@ import {
type AgentSessionEvent, type AgentSessionEvent,
type ToolDefinition, type ToolDefinition,
} from '@mariozechner/pi-coding-agent'; } from '@mariozechner/pi-coding-agent';
import type { Brain } from '@mosaic/brain'; import type { Brain } from '@mosaicstack/brain';
import type { Memory } from '@mosaic/memory'; import type { Memory } from '@mosaicstack/memory';
import { BRAIN } from '../brain/brain.tokens.js'; import { BRAIN } from '../brain/brain.tokens.js';
import { MEMORY } from '../memory/memory.tokens.js'; import { MEMORY } from '../memory/memory.tokens.js';
import { EmbeddingService } from '../memory/embedding.service.js'; import { EmbeddingService } from '../memory/embedding.service.js';

View File

@@ -1,4 +1,4 @@
import type { ModelCapability } from '@mosaic/types'; import type { ModelCapability } from '@mosaicstack/types';
/** /**
* Comprehensive capability matrix for all target models. * Comprehensive capability matrix for all target models.

View File

@@ -1,7 +1,7 @@
import { Inject, Injectable, Logger } from '@nestjs/common'; import { Inject, Injectable, Logger } from '@nestjs/common';
import { createCipheriv, createDecipheriv, createHash, randomBytes } from 'node:crypto'; import { createCipheriv, createDecipheriv, createHash, randomBytes } from 'node:crypto';
import type { Db } from '@mosaic/db'; import type { Db } from '@mosaicstack/db';
import { providerCredentials, eq, and } from '@mosaic/db'; import { providerCredentials, eq, and } from '@mosaicstack/db';
import { DB } from '../database/database.module.js'; import { DB } from '../database/database.module.js';
import type { ProviderCredentialSummaryDto } from './provider-credentials.dto.js'; import type { ProviderCredentialSummaryDto } from './provider-credentials.dto.js';

View File

@@ -14,7 +14,7 @@ import type {
ModelInfo, ModelInfo,
ProviderHealth, ProviderHealth,
ProviderInfo, ProviderInfo,
} from '@mosaic/types'; } from '@mosaicstack/types';
import { import {
AnthropicAdapter, AnthropicAdapter,
OllamaAdapter, OllamaAdapter,

View File

@@ -1,5 +1,5 @@
import { Body, Controller, Delete, Get, Inject, Param, Post, UseGuards } from '@nestjs/common'; import { Body, Controller, Delete, Get, Inject, Param, Post, UseGuards } from '@nestjs/common';
import type { RoutingCriteria } from '@mosaic/types'; import type { RoutingCriteria } from '@mosaicstack/types';
import { AuthGuard } from '../auth/auth.guard.js'; import { AuthGuard } from '../auth/auth.guard.js';
import { CurrentUser } from '../auth/current-user.decorator.js'; import { CurrentUser } from '../auth/current-user.decorator.js';
import { ProviderService } from './provider.service.js'; import { ProviderService } from './provider.service.js';

View File

@@ -1,6 +1,6 @@
import { Inject, Injectable, Logger } from '@nestjs/common'; import { Inject, Injectable, Logger } from '@nestjs/common';
import type { ModelInfo } from '@mosaic/types'; import type { ModelInfo } from '@mosaicstack/types';
import type { RoutingCriteria, RoutingResult, CostTier } from '@mosaic/types'; import type { RoutingCriteria, RoutingResult, CostTier } from '@mosaicstack/types';
import { ProviderService } from './provider.service.js'; import { ProviderService } from './provider.service.js';
/** Per-million-token cost thresholds for tier classification */ /** Per-million-token cost thresholds for tier classification */

View File

@@ -1,5 +1,5 @@
import { Inject, Injectable, Logger, type OnModuleInit } from '@nestjs/common'; import { Inject, Injectable, Logger, type OnModuleInit } from '@nestjs/common';
import { routingRules, type Db, sql } from '@mosaic/db'; import { routingRules, type Db, sql } from '@mosaicstack/db';
import { DB } from '../../database/database.module.js'; import { DB } from '../../database/database.module.js';
import type { RoutingCondition, RoutingAction } from './routing.types.js'; import type { RoutingCondition, RoutingAction } from './routing.types.js';

View File

@@ -1,5 +1,5 @@
import { Inject, Injectable, Logger } from '@nestjs/common'; import { Inject, Injectable, Logger } from '@nestjs/common';
import { routingRules, type Db, and, asc, eq, or } from '@mosaic/db'; import { routingRules, type Db, and, asc, eq, or } from '@mosaicstack/db';
import { DB } from '../../database/database.module.js'; import { DB } from '../../database/database.module.js';
import { ProviderService } from '../provider.service.js'; import { ProviderService } from '../provider.service.js';
import { classifyTask } from './task-classifier.js'; import { classifyTask } from './task-classifier.js';

View File

@@ -13,7 +13,7 @@ import {
Post, Post,
UseGuards, UseGuards,
} from '@nestjs/common'; } from '@nestjs/common';
import { routingRules, type Db, and, asc, eq, or, inArray } from '@mosaic/db'; import { routingRules, type Db, and, asc, eq, or, inArray } from '@mosaicstack/db';
import { DB } from '../../database/database.module.js'; import { DB } from '../../database/database.module.js';
import { AuthGuard } from '../../auth/auth.guard.js'; import { AuthGuard } from '../../auth/auth.guard.js';
import { CurrentUser } from '../../auth/current-user.decorator.js'; import { CurrentUser } from '../../auth/current-user.decorator.js';

View File

@@ -1,7 +1,7 @@
/** /**
* Routing engine types — M4-002 (condition types) and M4-003 (action types). * Routing engine types — M4-002 (condition types) and M4-003 (action types).
* *
* These types are re-exported from `@mosaic/types` for shared use across packages. * These types are re-exported from `@mosaicstack/types` for shared use across packages.
*/ */
// ─── Classification primitives ─────────────────────────────────────────────── // ─── Classification primitives ───────────────────────────────────────────────
@@ -23,7 +23,7 @@ export type Domain = 'frontend' | 'backend' | 'devops' | 'docs' | 'general';
/** /**
* Cost tier for model selection. * Cost tier for model selection.
* Extends the existing `CostTier` in `@mosaic/types` with `local` for self-hosted models. * Extends the existing `CostTier` in `@mosaicstack/types` with `local` for self-hosted models.
*/ */
export type CostTier = 'cheap' | 'standard' | 'premium' | 'local'; export type CostTier = 'cheap' | 'standard' | 'premium' | 'local';

View File

@@ -1,6 +1,6 @@
import { Type } from '@sinclair/typebox'; import { Type } from '@sinclair/typebox';
import type { ToolDefinition } from '@mariozechner/pi-coding-agent'; import type { ToolDefinition } from '@mariozechner/pi-coding-agent';
import type { Brain } from '@mosaic/brain'; import type { Brain } from '@mosaicstack/brain';
export function createBrainTools(brain: Brain): ToolDefinition[] { export function createBrainTools(brain: Brain): ToolDefinition[] {
const listProjects: ToolDefinition = { const listProjects: ToolDefinition = {

View File

@@ -1,7 +1,7 @@
import { Type } from '@sinclair/typebox'; import { Type } from '@sinclair/typebox';
import type { ToolDefinition } from '@mariozechner/pi-coding-agent'; import type { ToolDefinition } from '@mariozechner/pi-coding-agent';
import type { Memory } from '@mosaic/memory'; import type { Memory } from '@mosaicstack/memory';
import type { EmbeddingProvider } from '@mosaic/memory'; import type { EmbeddingProvider } from '@mosaicstack/memory';
/** /**
* Create memory tools bound to the session's authenticated userId. * Create memory tools bound to the session's authenticated userId.

View File

@@ -1,6 +1,6 @@
import type { IncomingMessage, ServerResponse } from 'node:http'; import type { IncomingMessage, ServerResponse } from 'node:http';
import { toNodeHandler } from 'better-auth/node'; import { toNodeHandler } from 'better-auth/node';
import type { Auth } from '@mosaic/auth'; import type { Auth } from '@mosaicstack/auth';
import type { NestFastifyApplication } from '@nestjs/platform-fastify'; import type { NestFastifyApplication } from '@nestjs/platform-fastify';
import { AUTH } from './auth.tokens.js'; import { AUTH } from './auth.tokens.js';

View File

@@ -6,7 +6,7 @@ import {
UnauthorizedException, UnauthorizedException,
} from '@nestjs/common'; } from '@nestjs/common';
import { fromNodeHeaders } from 'better-auth/node'; import { fromNodeHeaders } from 'better-auth/node';
import type { Auth } from '@mosaic/auth'; import type { Auth } from '@mosaicstack/auth';
import type { FastifyRequest } from 'fastify'; import type { FastifyRequest } from 'fastify';
import { AUTH } from './auth.tokens.js'; import { AUTH } from './auth.tokens.js';

View File

@@ -1,6 +1,6 @@
import { Global, Module } from '@nestjs/common'; import { Global, Module } from '@nestjs/common';
import { createAuth, type Auth } from '@mosaic/auth'; import { createAuth, type Auth } from '@mosaicstack/auth';
import type { Db } from '@mosaic/db'; import type { Db } from '@mosaicstack/db';
import { DB } from '../database/database.module.js'; import { DB } from '../database/database.module.js';
import { AUTH } from './auth.tokens.js'; import { AUTH } from './auth.tokens.js';
import { SsoController } from './sso.controller.js'; import { SsoController } from './sso.controller.js';

View File

@@ -1,5 +1,5 @@
import { Controller, Get } from '@nestjs/common'; import { Controller, Get } from '@nestjs/common';
import { buildSsoDiscovery, type SsoProviderDiscovery } from '@mosaic/auth'; import { buildSsoDiscovery, type SsoProviderDiscovery } from '@mosaicstack/auth';
@Controller('api/sso/providers') @Controller('api/sso/providers')
export class SsoController { export class SsoController {

View File

@@ -1,6 +1,6 @@
import { Global, Module } from '@nestjs/common'; import { Global, Module } from '@nestjs/common';
import { createBrain, type Brain } from '@mosaic/brain'; import { createBrain, type Brain } from '@mosaicstack/brain';
import type { Db } from '@mosaic/db'; import type { Db } from '@mosaicstack/db';
import { DB } from '../database/database.module.js'; import { DB } from '../database/database.module.js';
import { BRAIN } from './brain.tokens.js'; import { BRAIN } from './brain.tokens.js';

View File

@@ -11,15 +11,15 @@ import {
} from '@nestjs/websockets'; } from '@nestjs/websockets';
import { Server, Socket } from 'socket.io'; import { Server, Socket } from 'socket.io';
import type { AgentSessionEvent } from '@mariozechner/pi-coding-agent'; import type { AgentSessionEvent } from '@mariozechner/pi-coding-agent';
import type { Auth } from '@mosaic/auth'; import type { Auth } from '@mosaicstack/auth';
import type { Brain } from '@mosaic/brain'; import type { Brain } from '@mosaicstack/brain';
import type { import type {
SetThinkingPayload, SetThinkingPayload,
SlashCommandPayload, SlashCommandPayload,
SystemReloadPayload, SystemReloadPayload,
RoutingDecisionInfo, RoutingDecisionInfo,
AbortPayload, AbortPayload,
} from '@mosaic/types'; } from '@mosaicstack/types';
import { AgentService, type ConversationHistoryMessage } from '../agent/agent.service.js'; import { AgentService, type ConversationHistoryMessage } from '../agent/agent.service.js';
import { AUTH } from '../auth/auth.tokens.js'; import { AUTH } from '../auth/auth.tokens.js';
import { BRAIN } from '../brain/brain.tokens.js'; import { BRAIN } from '../brain/brain.tokens.js';

View File

@@ -1,6 +1,6 @@
import { describe, it, expect, vi, beforeEach } from 'vitest'; import { describe, it, expect, vi, beforeEach } from 'vitest';
import { CommandExecutorService } from './command-executor.service.js'; import { CommandExecutorService } from './command-executor.service.js';
import type { SlashCommandPayload } from '@mosaic/types'; import type { SlashCommandPayload } from '@mosaicstack/types';
// Minimal mock implementations // Minimal mock implementations
const mockRegistry = { const mockRegistry = {

View File

@@ -1,7 +1,7 @@
import { forwardRef, Inject, Injectable, Logger, Optional } from '@nestjs/common'; import { forwardRef, Inject, Injectable, Logger, Optional } from '@nestjs/common';
import type { QueueHandle } from '@mosaic/queue'; import type { QueueHandle } from '@mosaicstack/queue';
import type { Brain } from '@mosaic/brain'; import type { Brain } from '@mosaicstack/brain';
import type { SlashCommandPayload, SlashCommandResultPayload } from '@mosaic/types'; import type { SlashCommandPayload, SlashCommandResultPayload } from '@mosaicstack/types';
import { AgentService } from '../agent/agent.service.js'; import { AgentService } from '../agent/agent.service.js';
import { ChatGateway } from '../chat/chat.gateway.js'; import { ChatGateway } from '../chat/chat.gateway.js';
import { SessionGCService } from '../gc/session-gc.service.js'; import { SessionGCService } from '../gc/session-gc.service.js';

View File

@@ -1,6 +1,6 @@
import { describe, it, expect, beforeEach } from 'vitest'; import { describe, it, expect, beforeEach } from 'vitest';
import { CommandRegistryService } from './command-registry.service.js'; import { CommandRegistryService } from './command-registry.service.js';
import type { CommandDef } from '@mosaic/types'; import type { CommandDef } from '@mosaicstack/types';
const mockCmd: CommandDef = { const mockCmd: CommandDef = {
name: 'test', name: 'test',

View File

@@ -1,5 +1,5 @@
import { Injectable, type OnModuleInit } from '@nestjs/common'; import { Injectable, type OnModuleInit } from '@nestjs/common';
import type { CommandDef, CommandManifest } from '@mosaic/types'; import type { CommandDef, CommandManifest } from '@mosaicstack/types';
@Injectable() @Injectable()
export class CommandRegistryService implements OnModuleInit { export class CommandRegistryService implements OnModuleInit {

View File

@@ -13,7 +13,7 @@
import { describe, it, expect, vi, beforeEach } from 'vitest'; import { describe, it, expect, vi, beforeEach } from 'vitest';
import { CommandRegistryService } from './command-registry.service.js'; import { CommandRegistryService } from './command-registry.service.js';
import { CommandExecutorService } from './command-executor.service.js'; import { CommandExecutorService } from './command-executor.service.js';
import type { SlashCommandPayload } from '@mosaic/types'; import type { SlashCommandPayload } from '@mosaicstack/types';
// ─── Mocks ─────────────────────────────────────────────────────────────────── // ─── Mocks ───────────────────────────────────────────────────────────────────

View File

@@ -1,5 +1,5 @@
import { forwardRef, Inject, Module, type OnApplicationShutdown } from '@nestjs/common'; import { forwardRef, Inject, Module, type OnApplicationShutdown } from '@nestjs/common';
import { createQueue, type QueueHandle } from '@mosaic/queue'; import { createQueue, type QueueHandle } from '@mosaicstack/queue';
import { ChatModule } from '../chat/chat.module.js'; import { ChatModule } from '../chat/chat.module.js';
import { GCModule } from '../gc/gc.module.js'; import { GCModule } from '../gc/gc.module.js';
import { ReloadModule } from '../reload/reload.module.js'; import { ReloadModule } from '../reload/reload.module.js';

View File

@@ -1,5 +1,5 @@
import { Global, Module } from '@nestjs/common'; import { Global, Module } from '@nestjs/common';
import { loadConfig, type MosaicConfig } from '@mosaic/config'; import { loadConfig, type MosaicConfig } from '@mosaicstack/config';
export const MOSAIC_CONFIG = 'MOSAIC_CONFIG'; export const MOSAIC_CONFIG = 'MOSAIC_CONFIG';

View File

@@ -15,7 +15,7 @@ import {
Query, Query,
UseGuards, UseGuards,
} from '@nestjs/common'; } from '@nestjs/common';
import type { Brain } from '@mosaic/brain'; import type { Brain } from '@mosaicstack/brain';
import { BRAIN } from '../brain/brain.tokens.js'; import { BRAIN } from '../brain/brain.tokens.js';
import { AuthGuard } from '../auth/auth.guard.js'; import { AuthGuard } from '../auth/auth.guard.js';
import { CurrentUser } from '../auth/current-user.decorator.js'; import { CurrentUser } from '../auth/current-user.decorator.js';

View File

@@ -8,7 +8,7 @@ import {
type MissionStatusSummary, type MissionStatusSummary,
type MissionTask, type MissionTask,
type TaskDetail, type TaskDetail,
} from '@mosaic/coord'; } from '@mosaicstack/coord';
import { promises as fs } from 'node:fs'; import { promises as fs } from 'node:fs';
import path from 'node:path'; import path from 'node:path';

View File

@@ -2,9 +2,9 @@ import { mkdirSync } from 'node:fs';
import { homedir } from 'node:os'; import { homedir } from 'node:os';
import { join } from 'node:path'; import { join } from 'node:path';
import { Global, Inject, Module, type OnApplicationShutdown } from '@nestjs/common'; import { Global, Inject, Module, type OnApplicationShutdown } from '@nestjs/common';
import { createDb, createPgliteDb, type Db, type DbHandle } from '@mosaic/db'; import { createDb, createPgliteDb, type Db, type DbHandle } from '@mosaicstack/db';
import { createStorageAdapter, type StorageAdapter } from '@mosaic/storage'; import { createStorageAdapter, type StorageAdapter } from '@mosaicstack/storage';
import type { MosaicConfig } from '@mosaic/config'; import type { MosaicConfig } from '@mosaicstack/config';
import { MOSAIC_CONFIG } from '../config/config.module.js'; import { MOSAIC_CONFIG } from '../config/config.module.js';
export const DB_HANDLE = 'DB_HANDLE'; export const DB_HANDLE = 'DB_HANDLE';

View File

@@ -1,5 +1,5 @@
import { Module, type OnApplicationShutdown, Inject } from '@nestjs/common'; import { Module, type OnApplicationShutdown, Inject } from '@nestjs/common';
import { createQueue, type QueueHandle } from '@mosaic/queue'; import { createQueue, type QueueHandle } from '@mosaicstack/queue';
import { SessionGCService } from './session-gc.service.js'; import { SessionGCService } from './session-gc.service.js';
import { REDIS } from './gc.tokens.js'; import { REDIS } from './gc.tokens.js';

View File

@@ -1,7 +1,7 @@
import { describe, it, expect, vi, beforeEach } from 'vitest'; import { describe, it, expect, vi, beforeEach } from 'vitest';
import { Logger } from '@nestjs/common'; import { Logger } from '@nestjs/common';
import type { QueueHandle } from '@mosaic/queue'; import type { QueueHandle } from '@mosaicstack/queue';
import type { LogService } from '@mosaic/log'; import type { LogService } from '@mosaicstack/log';
import { SessionGCService } from './session-gc.service.js'; import { SessionGCService } from './session-gc.service.js';
type MockRedis = { type MockRedis = {

View File

@@ -1,6 +1,6 @@
import { Inject, Injectable, Logger, type OnModuleInit } from '@nestjs/common'; import { Inject, Injectable, Logger, type OnModuleInit } from '@nestjs/common';
import type { QueueHandle } from '@mosaic/queue'; import type { QueueHandle } from '@mosaicstack/queue';
import type { LogService } from '@mosaic/log'; import type { LogService } from '@mosaicstack/log';
import { LOG_SERVICE } from '../log/log.tokens.js'; import { LOG_SERVICE } from '../log/log.tokens.js';
import { REDIS } from './gc.tokens.js'; import { REDIS } from './gc.tokens.js';

View File

@@ -1,5 +1,5 @@
import { Body, Controller, Get, Inject, Param, Post, Query, UseGuards } from '@nestjs/common'; import { Body, Controller, Get, Inject, Param, Post, Query, UseGuards } from '@nestjs/common';
import type { LogService } from '@mosaic/log'; import type { LogService } from '@mosaicstack/log';
import { LOG_SERVICE } from './log.tokens.js'; import { LOG_SERVICE } from './log.tokens.js';
import { AuthGuard } from '../auth/auth.guard.js'; import { AuthGuard } from '../auth/auth.guard.js';
import type { IngestLogDto, QueryLogsDto } from './log.dto.js'; import type { IngestLogDto, QueryLogsDto } from './log.dto.js';

View File

@@ -1,6 +1,6 @@
import { Global, Module } from '@nestjs/common'; import { Global, Module } from '@nestjs/common';
import { createLogService, type LogService } from '@mosaic/log'; import { createLogService, type LogService } from '@mosaicstack/log';
import type { Db } from '@mosaic/db'; import type { Db } from '@mosaicstack/db';
import { DB } from '../database/database.module.js'; import { DB } from '../database/database.module.js';
import { LOG_SERVICE } from './log.tokens.js'; import { LOG_SERVICE } from './log.tokens.js';
import { LogController } from './log.controller.js'; import { LogController } from './log.controller.js';

View File

@@ -1,11 +1,11 @@
import { Inject, Injectable, Logger } from '@nestjs/common'; import { Inject, Injectable, Logger } from '@nestjs/common';
import type { LogService } from '@mosaic/log'; import type { LogService } from '@mosaicstack/log';
import type { Memory } from '@mosaic/memory'; import type { Memory } from '@mosaicstack/memory';
import { LOG_SERVICE } from './log.tokens.js'; import { LOG_SERVICE } from './log.tokens.js';
import { MEMORY } from '../memory/memory.tokens.js'; import { MEMORY } from '../memory/memory.tokens.js';
import { EmbeddingService } from '../memory/embedding.service.js'; import { EmbeddingService } from '../memory/embedding.service.js';
import type { Db } from '@mosaic/db'; import type { Db } from '@mosaicstack/db';
import { sql, summarizationJobs } from '@mosaic/db'; import { sql, summarizationJobs } from '@mosaicstack/db';
import { DB } from '../database/database.module.js'; import { DB } from '../database/database.module.js';
const SUMMARIZATION_PROMPT = `You are a knowledge extraction assistant. Given the following agent interaction logs, extract the key decisions, learnings, and patterns. Output a concise summary (2-4 sentences) that captures the most important information for future reference. Focus on actionable insights, not raw events. const SUMMARIZATION_PROMPT = `You are a knowledge extraction assistant. Given the following agent interaction logs, extract the key decisions, learnings, and patterns. Output a concise summary (2-4 sentences) that captures the most important information for future reference. Focus on actionable insights, not raw events.

View File

@@ -19,7 +19,7 @@ import { NestFactory } from '@nestjs/core';
import { Logger, ValidationPipe } from '@nestjs/common'; import { Logger, ValidationPipe } from '@nestjs/common';
import { FastifyAdapter, type NestFastifyApplication } from '@nestjs/platform-fastify'; import { FastifyAdapter, type NestFastifyApplication } from '@nestjs/platform-fastify';
import helmet from '@fastify/helmet'; import helmet from '@fastify/helmet';
import { listSsoStartupWarnings } from '@mosaic/auth'; import { listSsoStartupWarnings } from '@mosaicstack/auth';
import { AppModule } from './app.module.js'; import { AppModule } from './app.module.js';
import { mountAuthHandler } from './auth/auth.controller.js'; import { mountAuthHandler } from './auth/auth.controller.js';
import { mountMcpHandler } from './mcp/mcp.controller.js'; import { mountMcpHandler } from './mcp/mcp.controller.js';

View File

@@ -1,7 +1,7 @@
import type { IncomingMessage, ServerResponse } from 'node:http'; import type { IncomingMessage, ServerResponse } from 'node:http';
import { Logger } from '@nestjs/common'; import { Logger } from '@nestjs/common';
import { fromNodeHeaders } from 'better-auth/node'; import { fromNodeHeaders } from 'better-auth/node';
import type { Auth } from '@mosaic/auth'; import type { Auth } from '@mosaicstack/auth';
import type { NestFastifyApplication } from '@nestjs/platform-fastify'; import type { NestFastifyApplication } from '@nestjs/platform-fastify';
import type { McpService } from './mcp.service.js'; import type { McpService } from './mcp.service.js';
import { AUTH } from '../auth/auth.tokens.js'; import { AUTH } from '../auth/auth.tokens.js';

View File

@@ -3,8 +3,8 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'; import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
import { randomUUID } from 'node:crypto'; import { randomUUID } from 'node:crypto';
import { z } from 'zod'; import { z } from 'zod';
import type { Brain } from '@mosaic/brain'; import type { Brain } from '@mosaicstack/brain';
import type { Memory } from '@mosaic/memory'; import type { Memory } from '@mosaicstack/memory';
import { BRAIN } from '../brain/brain.tokens.js'; import { BRAIN } from '../brain/brain.tokens.js';
import { MEMORY } from '../memory/memory.tokens.js'; import { MEMORY } from '../memory/memory.tokens.js';
import { EmbeddingService } from '../memory/embedding.service.js'; import { EmbeddingService } from '../memory/embedding.service.js';

View File

@@ -1,5 +1,5 @@
import { Injectable, Logger } from '@nestjs/common'; import { Injectable, Logger } from '@nestjs/common';
import type { EmbeddingProvider } from '@mosaic/memory'; import type { EmbeddingProvider } from '@mosaicstack/memory';
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Environment-driven configuration // Environment-driven configuration

View File

@@ -12,7 +12,7 @@ import {
Query, Query,
UseGuards, UseGuards,
} from '@nestjs/common'; } from '@nestjs/common';
import type { Memory } from '@mosaic/memory'; import type { Memory } from '@mosaicstack/memory';
import { MEMORY } from './memory.tokens.js'; import { MEMORY } from './memory.tokens.js';
import { AuthGuard } from '../auth/auth.guard.js'; import { AuthGuard } from '../auth/auth.guard.js';
import { CurrentUser } from '../auth/current-user.decorator.js'; import { CurrentUser } from '../auth/current-user.decorator.js';

View File

@@ -5,10 +5,10 @@ import {
createMemoryAdapter, createMemoryAdapter,
type MemoryAdapter, type MemoryAdapter,
type MemoryConfig, type MemoryConfig,
} from '@mosaic/memory'; } from '@mosaicstack/memory';
import type { Db } from '@mosaic/db'; import type { Db } from '@mosaicstack/db';
import type { StorageAdapter } from '@mosaic/storage'; import type { StorageAdapter } from '@mosaicstack/storage';
import type { MosaicConfig } from '@mosaic/config'; import type { MosaicConfig } from '@mosaicstack/config';
import { MOSAIC_CONFIG } from '../config/config.module.js'; import { MOSAIC_CONFIG } from '../config/config.module.js';
import { DB, STORAGE_ADAPTER } from '../database/database.module.js'; import { DB, STORAGE_ADAPTER } from '../database/database.module.js';
import { MEMORY } from './memory.tokens.js'; import { MEMORY } from './memory.tokens.js';

View File

@@ -12,7 +12,7 @@ import {
Post, Post,
UseGuards, UseGuards,
} from '@nestjs/common'; } from '@nestjs/common';
import type { Brain } from '@mosaic/brain'; import type { Brain } from '@mosaicstack/brain';
import { BRAIN } from '../brain/brain.tokens.js'; import { BRAIN } from '../brain/brain.tokens.js';
import { AuthGuard } from '../auth/auth.guard.js'; import { AuthGuard } from '../auth/auth.guard.js';
import { CurrentUser } from '../auth/current-user.decorator.js'; import { CurrentUser } from '../auth/current-user.decorator.js';

View File

@@ -6,8 +6,8 @@ import {
type OnModuleDestroy, type OnModuleDestroy,
type OnModuleInit, type OnModuleInit,
} from '@nestjs/common'; } from '@nestjs/common';
import { DiscordPlugin } from '@mosaic/discord-plugin'; import { DiscordPlugin } from '@mosaicstack/discord-plugin';
import { TelegramPlugin } from '@mosaic/telegram-plugin'; import { TelegramPlugin } from '@mosaicstack/telegram-plugin';
import { PluginService } from './plugin.service.js'; import { PluginService } from './plugin.service.js';
import type { IChannelPlugin } from './plugin.interface.js'; import type { IChannelPlugin } from './plugin.interface.js';
import { PLUGIN_REGISTRY } from './plugin.tokens.js'; import { PLUGIN_REGISTRY } from './plugin.tokens.js';

View File

@@ -1,6 +1,6 @@
import { describe, it, expect, vi } from 'vitest'; import { describe, it, expect, vi } from 'vitest';
import { PreferencesService, PLATFORM_DEFAULTS, IMMUTABLE_KEYS } from './preferences.service.js'; import { PreferencesService, PLATFORM_DEFAULTS, IMMUTABLE_KEYS } from './preferences.service.js';
import type { Db } from '@mosaic/db'; import type { Db } from '@mosaicstack/db';
/** /**
* Build a mock Drizzle DB where the select chain supports: * Build a mock Drizzle DB where the select chain supports:

View File

@@ -1,5 +1,5 @@
import { Inject, Injectable, Logger } from '@nestjs/common'; import { Inject, Injectable, Logger } from '@nestjs/common';
import { eq, and, sql, type Db, preferences as preferencesTable } from '@mosaic/db'; import { eq, and, sql, type Db, preferences as preferencesTable } from '@mosaicstack/db';
import { DB } from '../database/database.module.js'; import { DB } from '../database/database.module.js';
export const PLATFORM_DEFAULTS: Record<string, unknown> = { export const PLATFORM_DEFAULTS: Record<string, unknown> = {

View File

@@ -1,5 +1,5 @@
import { Injectable, Logger } from '@nestjs/common'; import { Injectable, Logger } from '@nestjs/common';
import { createQueue, type QueueHandle } from '@mosaic/queue'; import { createQueue, type QueueHandle } from '@mosaicstack/queue';
const SESSION_SYSTEM_KEY = (sessionId: string) => `mosaic:session:${sessionId}:system`; const SESSION_SYSTEM_KEY = (sessionId: string) => `mosaic:session:${sessionId}:system`;
const SESSION_SYSTEM_FRAGMENTS_KEY = (sessionId: string) => const SESSION_SYSTEM_FRAGMENTS_KEY = (sessionId: string) =>

View File

@@ -13,7 +13,7 @@ import {
Post, Post,
UseGuards, UseGuards,
} from '@nestjs/common'; } from '@nestjs/common';
import type { Brain } from '@mosaic/brain'; import type { Brain } from '@mosaicstack/brain';
import { BRAIN } from '../brain/brain.tokens.js'; import { BRAIN } from '../brain/brain.tokens.js';
import { AuthGuard } from '../auth/auth.guard.js'; import { AuthGuard } from '../auth/auth.guard.js';
import { CurrentUser } from '../auth/current-user.decorator.js'; import { CurrentUser } from '../auth/current-user.decorator.js';

View File

@@ -1,6 +1,6 @@
import { Global, Module } from '@nestjs/common'; import { Global, Module } from '@nestjs/common';
import { createQueueAdapter, type QueueAdapter } from '@mosaic/queue'; import { createQueueAdapter, type QueueAdapter } from '@mosaicstack/queue';
import type { MosaicConfig } from '@mosaic/config'; import type { MosaicConfig } from '@mosaicstack/config';
import { MOSAIC_CONFIG } from '../config/config.module.js'; import { MOSAIC_CONFIG } from '../config/config.module.js';
import { QueueService } from './queue.service.js'; import { QueueService } from './queue.service.js';

View File

@@ -7,7 +7,7 @@ import {
type OnModuleDestroy, type OnModuleDestroy,
} from '@nestjs/common'; } from '@nestjs/common';
import { Queue, Worker, type Job, type ConnectionOptions } from 'bullmq'; import { Queue, Worker, type Job, type ConnectionOptions } from 'bullmq';
import type { LogService } from '@mosaic/log'; import type { LogService } from '@mosaicstack/log';
import { LOG_SERVICE } from '../log/log.tokens.js'; import { LOG_SERVICE } from '../log/log.tokens.js';
import type { JobDto, JobStatus } from './queue-admin.dto.js'; import type { JobDto, JobStatus } from './queue-admin.dto.js';

View File

@@ -1,5 +1,5 @@
import { Controller, HttpCode, HttpStatus, Inject, Post, UseGuards } from '@nestjs/common'; import { Controller, HttpCode, HttpStatus, Inject, Post, UseGuards } from '@nestjs/common';
import type { SystemReloadPayload } from '@mosaic/types'; import type { SystemReloadPayload } from '@mosaicstack/types';
import { AdminGuard } from '../admin/admin.guard.js'; import { AdminGuard } from '../admin/admin.guard.js';
import { ChatGateway } from '../chat/chat.gateway.js'; import { ChatGateway } from '../chat/chat.gateway.js';
import { ReloadService } from './reload.service.js'; import { ReloadService } from './reload.service.js';

View File

@@ -5,7 +5,7 @@ import {
type OnApplicationBootstrap, type OnApplicationBootstrap,
type OnApplicationShutdown, type OnApplicationShutdown,
} from '@nestjs/common'; } from '@nestjs/common';
import type { SystemReloadPayload } from '@mosaic/types'; import type { SystemReloadPayload } from '@mosaicstack/types';
import { CommandRegistryService } from '../commands/command-registry.service.js'; import { CommandRegistryService } from '../commands/command-registry.service.js';
import { isMosaicPlugin } from './mosaic-plugin.interface.js'; import { isMosaicPlugin } from './mosaic-plugin.interface.js';

View File

@@ -1,5 +1,5 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { eq, type Db, skills } from '@mosaic/db'; import { eq, type Db, skills } from '@mosaicstack/db';
import { DB } from '../database/database.module.js'; import { DB } from '../database/database.module.js';
type Skill = typeof skills.$inferSelect; type Skill = typeof skills.$inferSelect;

View File

@@ -14,7 +14,7 @@ import {
Query, Query,
UseGuards, UseGuards,
} from '@nestjs/common'; } from '@nestjs/common';
import type { Brain } from '@mosaic/brain'; import type { Brain } from '@mosaicstack/brain';
import { BRAIN } from '../brain/brain.tokens.js'; import { BRAIN } from '../brain/brain.tokens.js';
import { AuthGuard } from '../auth/auth.guard.js'; import { AuthGuard } from '../auth/auth.guard.js';
import { CurrentUser } from '../auth/current-user.decorator.js'; import { CurrentUser } from '../auth/current-user.decorator.js';

View File

@@ -1,5 +1,5 @@
import { Inject, Injectable, Logger } from '@nestjs/common'; import { Inject, Injectable, Logger } from '@nestjs/common';
import type { Brain } from '@mosaic/brain'; import type { Brain } from '@mosaicstack/brain';
import { BRAIN } from '../brain/brain.tokens.js'; import { BRAIN } from '../brain/brain.tokens.js';
import { PluginService } from '../plugin/plugin.service.js'; import { PluginService } from '../plugin/plugin.service.js';
import { WorkspaceService } from './workspace.service.js'; import { WorkspaceService } from './workspace.service.js';

View File

@@ -1,5 +1,5 @@
import { Inject, Injectable, Logger } from '@nestjs/common'; import { Inject, Injectable, Logger } from '@nestjs/common';
import { eq, and, type Db, teams, teamMembers, projects } from '@mosaic/db'; import { eq, and, type Db, teams, teamMembers, projects } from '@mosaicstack/db';
import { DB } from '../database/database.module.js'; import { DB } from '../database/database.module.js';
@Injectable() @Injectable()

View File

@@ -4,15 +4,15 @@
"rootDir": "../..", "rootDir": "../..",
"baseUrl": ".", "baseUrl": ".",
"paths": { "paths": {
"@mosaic/auth": ["../../packages/auth/src/index.ts"], "@mosaicstack/auth": ["../../packages/auth/src/index.ts"],
"@mosaic/brain": ["../../packages/brain/src/index.ts"], "@mosaicstack/brain": ["../../packages/brain/src/index.ts"],
"@mosaic/coord": ["../../packages/coord/src/index.ts"], "@mosaicstack/coord": ["../../packages/coord/src/index.ts"],
"@mosaic/db": ["../../packages/db/src/index.ts"], "@mosaicstack/db": ["../../packages/db/src/index.ts"],
"@mosaic/log": ["../../packages/log/src/index.ts"], "@mosaicstack/log": ["../../packages/log/src/index.ts"],
"@mosaic/memory": ["../../packages/memory/src/index.ts"], "@mosaicstack/memory": ["../../packages/memory/src/index.ts"],
"@mosaic/types": ["../../packages/types/src/index.ts"], "@mosaicstack/types": ["../../packages/types/src/index.ts"],
"@mosaic/discord-plugin": ["../../plugins/discord/src/index.ts"], "@mosaicstack/discord-plugin": ["../../plugins/discord/src/index.ts"],
"@mosaic/telegram-plugin": ["../../plugins/telegram/src/index.ts"] "@mosaicstack/telegram-plugin": ["../../plugins/telegram/src/index.ts"]
} }
} }
} }

View File

@@ -2,7 +2,7 @@ import type { NextConfig } from 'next';
const nextConfig: NextConfig = { const nextConfig: NextConfig = {
output: 'standalone', output: 'standalone',
transpilePackages: ['@mosaic/design-tokens'], transpilePackages: ['@mosaicstack/design-tokens'],
// Enable gzip/brotli compression for all responses. // Enable gzip/brotli compression for all responses.
compress: true, compress: true,

View File

@@ -1,5 +1,5 @@
{ {
"name": "@mosaic/web", "name": "@mosaicstack/web",
"version": "0.0.2", "version": "0.0.2",
"private": true, "private": true,
"scripts": { "scripts": {
@@ -12,7 +12,7 @@
"start": "next start" "start": "next start"
}, },
"dependencies": { "dependencies": {
"@mosaic/design-tokens": "workspace:^", "@mosaicstack/design-tokens": "workspace:^",
"better-auth": "^1.5.5", "better-auth": "^1.5.5",
"clsx": "^2.1.0", "clsx": "^2.1.0",
"next": "^16.0.0", "next": "^16.0.0",

View File

@@ -7,7 +7,7 @@ import { defineConfig, devices } from '@playwright/test';
* - Next.js web app running on http://localhost:3000 * - Next.js web app running on http://localhost:3000
* - NestJS gateway running on http://localhost:14242 * - NestJS gateway running on http://localhost:14242
* *
* Run with: pnpm --filter @mosaic/web test:e2e * Run with: pnpm --filter @mosaicstack/web test:e2e
*/ */
export default defineConfig({ export default defineConfig({
testDir: './e2e', testDir: './e2e',

View File

@@ -1,70 +1,72 @@
# Mission Manifest — Harness Foundation # Mission Manifest — CLI Unification & E2E First-Run
> Persistent document tracking full mission scope, status, and session history. > Persistent document tracking full mission scope, status, and session history.
> Updated by the orchestrator at each phase transition and milestone completion. > Updated by the orchestrator at each phase transition and milestone completion.
## Mission ## Mission
**ID:** harness-20260321 **ID:** cli-unification-20260404
**Statement:** Transform Mosaic Stack from a functional demo into a real multi-provider, task-routing AI harness. Persist all conversations, integrate frontier LLM providers (Anthropic, OpenAI, OpenRouter, Z.ai, Ollama), build granular task-aware agent routing, harden agent sessions, replace cron with BullMQ, and design the channel protocol for future Matrix/remote integration. **Statement:** Transform the Mosaic CLI from a partially-duplicated, manually-assembled experience into a single cohesive entry point that installs, configures, and controls the entire Mosaic system. Every Mosaic package gets first-class CLI surface. The first-run experience works end-to-end with no manual stitching. Gateway token recovery is possible without the web UI. Opt-in telemetry uses the published telemetry clients.
**Phase:** Complete **Phase:** Complete
**Current Milestone:** All milestones done **Current Milestone:**
**Progress:** 7 / 7 milestones **Progress:** 8 / 8 milestones
**Status:** complete **Status:** completed
**Last Updated:** 2026-03-22 UTC **Last Updated:** 2026-04-05
**Release:** [`mosaic-v0.0.22`](https://git.mosaicstack.dev/mosaicstack/mosaic-stack/releases/tag/mosaic-v0.0.22) (`@mosaicstack/mosaic@0.0.22`, alpha — stays in 0.0.x until GA)
## Success Criteria ## Success Criteria
- [x] AC-1: Send messages in TUI → restart TUI → resume conversation → agent has full history and context - [x] AC-1: Fresh machine `bash <(curl …install.sh)` → single command lands on a working authenticated gateway with a usable admin token; no secondary manual wizards required
- [x] AC-2: Route a coding task to Claude Opus 4.6, a simple question to Haiku, a summarization to GLM-5 — all via granular routing rules - [x] AC-2: `mosaic --help` lists every sub-package as a top-level command and is alphabetized for readability
- [x] AC-3: Two users exist, User A's memory searches never return User B's data - [x] AC-3: `mosaic auth`, `mosaic brain`, `mosaic forge`, `mosaic log`, `mosaic macp`, `mosaic memory`, `mosaic queue`, `mosaic storage`, `mosaic telemetry` each expose at least one working subcommand that exercises the underlying package
- [x] AC-4: `/model claude-sonnet-4-6` in TUI switches the active model for subsequent messages - [x] AC-4: Gateway admin token can be rotated or recovered from the CLI alone — operator is never stranded because the web UI is inaccessible
- [x] AC-5: `/agent coding-agent` in TUI switches to a different agent with different system prompt and tools - [x] AC-5: `mosaic telemetry` uses the published `@mosaicstack/telemetry-client-js` (from the Gitea npm registry); local OTEL stays for wide-event logging / post-mortems; remote upload is opt-in and disabled by default
- [x] AC-6: BullMQ jobs execute on schedule, failures retry with backoff, admin can inspect via `/api/admin/jobs` - [x] AC-6: Install → wizard → gateway install → TUI verification flow is a single cohesive path with clear state transitions and no dead ends
- [x] AC-7: Channel protocol document exists with Matrix integration points defined, reviewed, and approved - [x] AC-7: `@mosaicstack/mosaic` is the sole `mosaic` binary owner; `@mosaicstack/cli` is gone from the repo and all docs
- [x] AC-8: Embeddings run on Ollama local models (no external API dependency for vector operations) - [x] AC-8: All milestones ship as merged PRs with green CI, closed issues, and updated release notes
- [x] AC-9: All five providers (Anthropic, OpenAI, OpenRouter, Z.ai, Ollama) connect, list models, and complete chat requests
- [x] AC-10: Routing transparency — TUI displays which model was selected and the routing reason for each response
## Milestones ## Milestones
| # | ID | Name | Status | Branch | Issue | Started | Completed | | # | ID | Name | Status | Branch | Issue | Started | Completed |
| --- | ------ | ---------------------------------- | ------ | ------ | --------- | ---------- | ---------- | | --- | ------ | ------------------------------------------------------------------------ | ------ | ----------------------------------- | --------------------------------- | ---------- | ---------- |
| 1 | ms-166 | Conversation Persistence & Context | done | — | #224#231 | 2026-03-21 | 2026-03-21 | | 1 | cu-m01 | Kill legacy @mosaicstack/cli package | done | chore/remove-cli-package-duplicate | #398 | 2026-04-04 | 2026-04-04 |
| 2 | ms-167 | Security & Isolation | done | — | #232#239 | 2026-03-21 | 2026-03-21 | | 2 | cu-m02 | Archive stale mission state + scaffold new mission | done | docs/mission-cli-unification | #399 | 2026-04-04 | 2026-04-04 |
| 3 | ms-168 | Provider Integration | done | — | #240#251 | 2026-03-21 | 2026-03-22 | | 3 | cu-m03 | Fix gateway bootstrap token recovery (server + CLI paths) | done | feat/gateway-token-recovery | #411, #414 | 2026-04-05 | 2026-04-05 |
| 4 | ms-169 | Agent Routing Engine | done | — | #252#264 | 2026-03-22 | 2026-03-22 | | 4 | cu-m04 | Alphabetize + group `mosaic --help` output | done | feat/help-sort + feat/mosaic-config | #402, #408 | 2026-04-05 | 2026-04-05 |
| 5 | ms-170 | Agent Session Hardening | done | — | #265#272 | 2026-03-22 | 2026-03-22 | | 5 | cu-m05 | Sub-package CLI surface (auth/brain/forge/log/macp/memory/queue/storage) | done | feat/mosaic-\*-cli (x9) | #403#407, #410, #412, #413, #415 | 2026-04-05 | 2026-04-05 |
| 6 | ms-171 | Job Queue Foundation | done | — | #273#280 | 2026-03-22 | 2026-03-22 | | 6 | cu-m06 | `mosaic telemetry` — local OTEL + opt-in remote upload | done | feat/mosaic-telemetry | #417 | 2026-04-05 | 2026-04-05 |
| 7 | ms-172 | Channel Protocol Design | done | — | #281#288 | 2026-03-22 | 2026-03-22 | | 7 | cu-m07 | Unified first-run UX (install.sh → wizard → gateway → TUI) | done | feat/mosaic-first-run-ux | #418 | 2026-04-05 | 2026-04-05 |
| 8 | cu-m08 | Docs refresh + release tag | done | docs/cli-unification-release-v0.1.0 | #419 | 2026-04-05 | 2026-04-05 |
## Deployment ## Deployment
| Target | URL | Method | | Target | URL | Method |
| -------------------- | --------- | -------------------------- | | -------------------- | --------- | ----------------------------------------------- |
| Docker Compose (dev) | localhost | docker compose up | | Local tier (default) | localhost | `mosaic gateway install` — pglite + local queue |
| Production | TBD | Docker Swarm via Portainer | | Team tier | any host | `mosaic gateway install` — PG + Valkey |
| Docker Compose (dev) | localhost | `docker compose up` for PG/Valkey/OTEL/Jaeger |
## Coordination ## Coordination
- **Primary Agent:** claude-opus-4-6 - **Primary Agent:** claude-opus-4-6[1m]
- **Sibling Agents:** sonnet (workers), haiku (verification) - **Sibling Agents:** sonnet (standard implementation), haiku (status/explore/verify), codex (coding-heavy tasks)
- **Shared Contracts:** docs/PRD-Harness_Foundation.md, docs/TASKS.md - **Shared Contracts:** `docs/PRD.md` (existing v0.1.0 PRD — still the long-term target), this manifest, `docs/TASKS.md`, `docs/scratchpads/cli-unification-20260404.md`
## Token Budget ## Token Budget
| Metric | Value | | Metric | Value |
| ------ | ------ | | ------ | ------ |
| Budget | | | Budget | TBD |
| Used | ~2.5M | | Used | ~80K |
| Mode | normal | | Mode | normal |
## Session History ## Session History
| Session | Runtime | Started | Duration | Ended Reason | Last Task | | Session | Runtime | Started | Duration | Ended Reason | Last Task |
| ------- | --------------- | ---------- | -------- | ------------ | ----------------- | | ------- | --------------- | ---------- | -------- | ---------------- | ------------------------------------------------------------ |
| 1 | claude-opus-4-6 | 2026-03-21 | ~6h | complete | M7-008 — all done | | 1 | claude-opus-4-6 | 2026-04-04 | ~4h | context-budget | cu-m01 + cu-m02 merged (#398, #399); open questions resolved |
| 2 | claude-opus-4-6 | 2026-04-05 | ~6h | mission-complete | cu-m03..cu-m08 all merged; mosaic-v0.1.0 released |
## Scratchpad ## Scratchpad
Path: `docs/scratchpads/harness-20260321.md` Path: `docs/scratchpads/cli-unification-20260404.md`

View File

@@ -153,7 +153,7 @@ for any `<Image>` components added in the future.
```bash ```bash
# Run the DB migration (requires a live DB) # Run the DB migration (requires a live DB)
pnpm --filter @mosaic/db exec drizzle-kit migrate pnpm --filter @mosaicstack/db exec drizzle-kit migrate
# Or, in Docker/Swarm — migrations run automatically on gateway startup # Or, in Docker/Swarm — migrations run automatically on gateway startup
# via runMigrations() in packages/db/src/migrate.ts # via runMigrations() in packages/db/src/migrate.ts

View File

@@ -57,7 +57,7 @@ Multi-panel layout with keyboard navigation.
- **Ink 5** (React for CLI) — already in deps - **Ink 5** (React for CLI) — already in deps
- **Component architecture** — break monolithic `app.tsx` into composable components - **Component architecture** — break monolithic `app.tsx` into composable components
- **Typed Socket.IO events** — leverage `@mosaic/types` `ServerToClientEvents` / `ClientToServerEvents` - **Typed Socket.IO events** — leverage `@mosaicstack/types` `ServerToClientEvents` / `ClientToServerEvents`
- **Local state only** (Wave 1) — cwd/branch read from `process.cwd()` and `git` at startup - **Local state only** (Wave 1) — cwd/branch read from `process.cwd()` and `git` at startup
- **Gateway metadata** (future) — extend socket handshake or add REST endpoint for model info, token usage - **Gateway metadata** (future) — extend socket handshake or add REST endpoint for model info, token usage

View File

@@ -8,7 +8,7 @@
- **Best-Guess Mode:** true - **Best-Guess Mode:** true
- Repo (target): `git.mosaicstack.dev/mosaic/mosaic-stack` - Repo (target): `git.mosaicstack.dev/mosaic/mosaic-stack`
- Baseline: `~/src/jarvis-old` (jarvis v0.2.0) - Baseline: `~/src/jarvis-old` (jarvis v0.2.0)
- Package source: `~/src/mosaic-mono-v0` (@mosaic/\* packages) - Package source: `~/src/mosaic-mono-v0` (@mosaicstack/\* packages)
- Agent harness: [pi](https://github.com/badlogic/pi-mono) (v0.57.1) - Agent harness: [pi](https://github.com/badlogic/pi-mono) (v0.57.1)
- Remote control reference: [OpenClaw](https://github.com/openclaw/openclaw) (upstream, canonical) - Remote control reference: [OpenClaw](https://github.com/openclaw/openclaw) (upstream, canonical)
@@ -16,7 +16,7 @@
## Problem Statement ## Problem Statement
Jarvis (v0.2.0) is a self-hosted AI assistant with a Python FastAPI backend and Next.js frontend. It handles chat, projects, tasks, and LLM routing but lacks orchestration depth, agent coordination, shared memory, and remote access. The Mosaic framework (`~/.config/mosaic`) provides agent guides, shell-based orchestration tools, and quality rails — but these are loose scripts, not an integrated platform. The `@mosaic/*` packages in mosaic-mono-v0 began consolidating these into TypeScript packages (brain, queue, coord, cli, prdy, quality-rails) but have no UI, no auth, and no agent runtime integration. Jarvis (v0.2.0) is a self-hosted AI assistant with a Python FastAPI backend and Next.js frontend. It handles chat, projects, tasks, and LLM routing but lacks orchestration depth, agent coordination, shared memory, and remote access. The Mosaic framework (`~/.config/mosaic`) provides agent guides, shell-based orchestration tools, and quality rails — but these are loose scripts, not an integrated platform. The `@mosaicstack/*` packages in mosaic-mono-v0 began consolidating these into TypeScript packages (brain, queue, coord, cli, prdy, quality-rails) but have no UI, no auth, and no agent runtime integration.
**The gap:** Three codebases with overlapping concerns, no unified runtime, no remote control surface (Discord/Telegram), no gateway orchestrator, and a Python backend that doesn't align with the target TypeScript-everywhere stack. **The gap:** Three codebases with overlapping concerns, no unified runtime, no remote control surface (Discord/Telegram), no gateway orchestrator, and a Python backend that doesn't align with the target TypeScript-everywhere stack.
@@ -32,7 +32,7 @@ Jarvis (v0.2.0) is a self-hosted AI assistant with a Python FastAPI backend and
4. **Gateway orchestrator** — Central routing layer that dispatches tasks to appropriate agents based on capability, cost, and context 4. **Gateway orchestrator** — Central routing layer that dispatches tasks to appropriate agents based on capability, cost, and context
5. **Shared memory** — PostgreSQL canonical store + vector DB for semantic search + tiered log summarization to prevent context creep 5. **Shared memory** — PostgreSQL canonical store + vector DB for semantic search + tiered log summarization to prevent context creep
6. **Multi-user with SSO** — BetterAuth with Authentik/WorkOS/Keycloak SSO, RBAC for family/team/business use 6. **Multi-user with SSO** — BetterAuth with Authentik/WorkOS/Keycloak SSO, RBAC for family/team/business use
7. **Full @mosaic/\* package integration** — brain, queue, coord, mosaic, prdy, quality-rails, cli all integrated 7. **Full @mosaicstack/\* package integration** — brain, queue, coord, mosaic, prdy, quality-rails, cli all integrated
8. **Extensible** — MCP capability, skill import interface, plugin architecture for LLM providers and remote channels 8. **Extensible** — MCP capability, skill import interface, plugin architecture for LLM providers and remote channels
--- ---
@@ -44,7 +44,7 @@ Jarvis (v0.2.0) is a self-hosted AI assistant with a Python FastAPI backend and
1. Chat/conversation UI (web) — carry forward from jarvis-old, rewrite frontend to work with new backend 1. Chat/conversation UI (web) — carry forward from jarvis-old, rewrite frontend to work with new backend
2. Pi TUI integration — terminal-based agent interaction using Pi SDK 2. Pi TUI integration — terminal-based agent interaction using Pi SDK
3. Web dashboard — settings, task management, projects, PRDs, missions, agent status 3. Web dashboard — settings, task management, projects, PRDs, missions, agent status
4. Gateway orchestrator (`@mosaic/gateway`) — central dispatch for agent tasks with routing logic 4. Gateway orchestrator (`@mosaicstack/gateway`) — central dispatch for agent tasks with routing logic
5. Task management — CRUD, kanban, mission-scoped tasks, dependency tracking 5. Task management — CRUD, kanban, mission-scoped tasks, dependency tracking
6. Project management — projects, milestones, PRDs linked to missions 6. Project management — projects, milestones, PRDs linked to missions
7. Shared memory system — learned preferences, behaviors, defaults; tiered storage with summarization 7. Shared memory system — learned preferences, behaviors, defaults; tiered storage with summarization
@@ -55,13 +55,13 @@ Jarvis (v0.2.0) is a self-hosted AI assistant with a Python FastAPI backend and
12. Agent routing — task-based model/provider selection (cost/capability matrix) 12. Agent routing — task-based model/provider selection (cost/capability matrix)
13. MCP capability — server and client, tool registration 13. MCP capability — server and client, tool registration
14. Skill import interface — browse, install, manage agent skills 14. Skill import interface — browse, install, manage agent skills
15. `@mosaic/brain` — structured data layer (migrated to PG + vector DB backend) 15. `@mosaicstack/brain` — structured data layer (migrated to PG + vector DB backend)
16. `@mosaic/queue` — Valkey-backed task queue with MCP tools 16. `@mosaicstack/queue` — Valkey-backed task queue with MCP tools
17. `@mosaic/coord` — mission coordination engine 17. `@mosaicstack/coord` — mission coordination engine
18. `@mosaic/mosaic` — install wizard / bootstrap 18. `@mosaicstack/mosaic` — install wizard / bootstrap
19. `@mosaic/prdy` — PRD wizard 19. `@mosaicstack/prdy` — PRD wizard
20. `@mosaic/quality-rails` — code quality scaffolder 20. `@mosaicstack/quality-rails` — code quality scaffolder
21. `@mosaic/cli` — unified `mosaic` CLI 21. `@mosaicstack/cli` — unified `mosaic` CLI
22. Docker Compose deployment + bare-metal capability 22. Docker Compose deployment + bare-metal capability
23. Agent log service — ingest, parse, tier, summarize agent interaction logs 23. Agent log service — ingest, parse, tier, summarize agent interaction logs
@@ -94,14 +94,14 @@ Jarvis (v0.2.0) is a self-hosted AI assistant with a Python FastAPI backend and
│ └──────────────┴───────┬───────┴────────────────┘ │ │ └──────────────┴───────┬───────┴────────────────┘ │
│ │ │ │ │ │
│ ┌─────────▼──────────┐ │ │ ┌─────────▼──────────┐ │
│ │ @mosaic/gateway │ ← Central Orchestrator│ │ │ @mosaicstack/gateway │ ← Central Orchestrator│
│ │ (NestJS+Fastify) │ │ │ │ (NestJS+Fastify) │ │
│ └────┬────┬────┬─────┘ │ │ └────┬────┬────┬─────┘ │
│ │ │ │ │ │ │ │ │ │
│ ┌──────────────┤ │ ├──────────────┐ │ │ ┌──────────────┤ │ ├──────────────┐ │
│ │ │ │ │ │ │ │ │ │ │ │ │ │
│ ┌───────▼──────┐ ┌────▼────▼──┐ │ ┌───────────▼────────┐ │ │ ┌───────▼──────┐ ┌────▼────▼──┐ │ ┌───────────▼────────┐ │
│ │ @mosaic/brain│ │ @mosaic/ │ │ │ Agent Pool │ │ │ │ @mosaicstack/brain│ │ @mosaicstack/ │ │ │ Agent Pool │ │
│ │ (Data Layer) │ │ queue │ │ │ (Pi SDK sessions) │ │ │ │ (Data Layer) │ │ queue │ │ │ (Pi SDK sessions) │ │
│ └───────┬──────┘ └────────────┘ │ │ - Anthropic │ │ │ └───────┬──────┘ └────────────┘ │ │ - Anthropic │ │
│ │ │ │ - Codex │ │ │ │ │ │ - Codex │ │
@@ -111,12 +111,12 @@ Jarvis (v0.2.0) is a self-hosted AI assistant with a Python FastAPI backend and
│ └──────────────┴───────────┘ │ │ - llama.cpp │ │ │ └──────────────┴───────────┘ │ │ - llama.cpp │ │
│ │ └────────────────────┘ │ │ │ └────────────────────┘ │
│ ┌─────────────▼──────┐ │ │ ┌─────────────▼──────┐ │
│ │ @mosaic/coord │ │ │ │ @mosaicstack/coord │ │
│ │ Mission lifecycle │ │ │ │ Mission lifecycle │ │
│ └────────────────────┘ │ │ └────────────────────┘ │
│ │ │ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │
│ │ @mosaic/cli │ │ @mosaic/prdy │ │ @mosaic/ │ │ │ │ @mosaicstack/cli │ │ @mosaicstack/prdy │ │ @mosaicstack/ │ │
│ │ │ │ │ │ quality-rails │ │ │ │ │ │ │ │ quality-rails │ │
│ └──────────────┘ └──────────────┘ └──────────────────┘ │ │ └──────────────┘ └──────────────┘ └──────────────────┘ │
│ │ │ │
@@ -130,20 +130,20 @@ Jarvis (v0.2.0) is a self-hosted AI assistant with a Python FastAPI backend and
| Layer | Technology | Rationale | | Layer | Technology | Rationale |
| ------------------ | ------------------------------------ | ----------------------------------------------------------------------------------------------------------- | | ------------------ | ------------------------------------ | ----------------------------------------------------------------------------------------------------------- |
| **Web Frontend** | Next.js 16 + React 19 + Tailwind CSS | SSR, RSC; design tokens from @mosaic/design-tokens (mosaic-stack-website) | | **Web Frontend** | Next.js 16 + React 19 + Tailwind CSS | SSR, RSC; design tokens from @mosaicstack/design-tokens (mosaic-stack-website) |
| **API / Gateway** | NestJS + Fastify adapter | Module system, DI, guards/interceptors for complex gateway; Fastify performance underneath | | **API / Gateway** | NestJS + Fastify adapter | Module system, DI, guards/interceptors for complex gateway; Fastify performance underneath |
| **Agent Runtime** | Pi SDK (embedded) | Extensible harness with tools, skills, session management | | **Agent Runtime** | Pi SDK (embedded) | Extensible harness with tools, skills, session management |
| **TUI** | Pi interactive mode | Native terminal agent interaction | | **TUI** | Pi interactive mode | Native terminal agent interaction |
| **Auth** | BetterAuth + SSO adapters | Multi-user RBAC with Authentik/WorkOS/Keycloak | | **Auth** | BetterAuth + SSO adapters | Multi-user RBAC with Authentik/WorkOS/Keycloak |
| **Database** | PostgreSQL 17 + pgvector | Canonical store; pgvector for embedding search | | **Database** | PostgreSQL 17 + pgvector | Canonical store; pgvector for embedding search |
| **Vector DB** | pgvector + VectorStore interface | pgvector for v0.1.0; `VectorStore` abstraction in @mosaic/memory makes Qdrant a drop-in later | | **Vector DB** | pgvector + VectorStore interface | pgvector for v0.1.0; `VectorStore` abstraction in @mosaicstack/memory makes Qdrant a drop-in later |
| **Cache / Queue** | Valkey 8 | Redis-compatible; proven in @mosaic/queue | | **Cache / Queue** | Valkey 8 | Redis-compatible; proven in @mosaicstack/queue |
| **ORM** | Drizzle ORM | TypeScript-native, lightweight, good migration story | | **ORM** | Drizzle ORM | TypeScript-native, lightweight, good migration story |
| **Validation** | Zod | Already used across @mosaic/\* packages | | **Validation** | Zod | Already used across @mosaicstack/\* packages |
| **Build** | pnpm workspaces + Turborepo | Proven in both jarvis-old and mosaic-mono-v0 | | **Build** | pnpm workspaces + Turborepo | Proven in both jarvis-old and mosaic-mono-v0 |
| **Testing** | Vitest + Playwright | Unit/integration via Vitest, E2E via Playwright | | **Testing** | Vitest + Playwright | Unit/integration via Vitest, E2E via Playwright |
| **Remote Control** | Discord.js + Telegraf | Inspired by OpenClaw plugin architecture | | **Remote Control** | Discord.js + Telegraf | Inspired by OpenClaw plugin architecture |
| **MCP** | @modelcontextprotocol/sdk | Already used in @mosaic/brain and @mosaic/queue | | **MCP** | @modelcontextprotocol/sdk | Already used in @mosaicstack/brain and @mosaicstack/queue |
| **Container** | Docker Compose | Self-hosted; bare-metal also supported | | **Container** | Docker Compose | Self-hosted; bare-metal also supported |
| **CI** | Woodpecker CI | Existing infrastructure at git.mosaicstack.dev | | **CI** | Woodpecker CI | Existing infrastructure at git.mosaicstack.dev |
| **Observability** | OpenTelemetry + SigNoz | Wide-event logging from day one; OTEL auto-instrumentation for NestJS/PG/HTTP; SigNoz as all-in-one backend | | **Observability** | OpenTelemetry + SigNoz | Wide-event logging from day one; OTEL auto-instrumentation for NestJS/PG/HTTP; SigNoz as all-in-one backend |
@@ -158,12 +158,12 @@ The jarvis-old FastAPI backend is not carried forward as code. Its domain logic
Instead of a custom LLM provider abstraction (jarvis-old's `BaseLLMProvider`), Pi SDK manages agent sessions. Pi handles model selection, tool calling, context management, and compaction. The gateway dispatches work to Pi sessions configured with appropriate providers. Instead of a custom LLM provider abstraction (jarvis-old's `BaseLLMProvider`), Pi SDK manages agent sessions. Pi handles model selection, tool calling, context management, and compaction. The gateway dispatches work to Pi sessions configured with appropriate providers.
**AD-3: Gateway as the central nervous system (NestJS + Fastify adapter)** **AD-3: Gateway as the central nervous system (NestJS + Fastify adapter)**
`@mosaic/gateway` is the single API surface. The web app, TUI, Discord, and Telegram all talk to the gateway. The gateway routes to brain (data), queue (coordination), agent pool (LLM work), and coord (mission lifecycle). This replaces the direct FastAPI-to-DB pattern from jarvis-old. `@mosaicstack/gateway` is the single API surface. The web app, TUI, Discord, and Telegram all talk to the gateway. The gateway routes to brain (data), queue (coordination), agent pool (LLM work), and coord (mission lifecycle). This replaces the direct FastAPI-to-DB pattern from jarvis-old.
NestJS was chosen over raw Fastify because the gateway is inherently complex — it hosts channel plugins, agent pool management, routing engine, WebSocket hub, MCP server, auth middleware, and integrates brain, queue, memory, and log services. NestJS provides the module system, dependency injection, guards, and interceptors needed to organize this cleanly. NestJS uses Fastify as its HTTP adapter, so Fastify's performance is preserved. This also aligns with the stated stack preference in USER.md ("NestJS API + Next.js web"). @mosaic/brain's existing Fastify code migrates naturally into a NestJS module with Fastify adapter. NestJS was chosen over raw Fastify because the gateway is inherently complex — it hosts channel plugins, agent pool management, routing engine, WebSocket hub, MCP server, auth middleware, and integrates brain, queue, memory, and log services. NestJS provides the module system, dependency injection, guards, and interceptors needed to organize this cleanly. NestJS uses Fastify as its HTTP adapter, so Fastify's performance is preserved. This also aligns with the stated stack preference in USER.md ("NestJS API + Next.js web"). @mosaicstack/brain's existing Fastify code migrates naturally into a NestJS module with Fastify adapter.
**AD-4: Brain migrates from JSON files to PostgreSQL** **AD-4: Brain migrates from JSON files to PostgreSQL**
`@mosaic/brain` currently uses a JSON file store. For Mosaic Stack, brain's data model (tasks, projects, events, agents, missions, tickets) moves to PostgreSQL via Drizzle ORM. Brain's REST + MCP interface is preserved — only the storage backend changes. `@mosaicstack/brain` currently uses a JSON file store. For Mosaic Stack, brain's data model (tasks, projects, events, agents, missions, tickets) moves to PostgreSQL via Drizzle ORM. Brain's REST + MCP interface is preserved — only the storage backend changes.
**AD-5: Tiered memory with summarization** **AD-5: Tiered memory with summarization**
Agent interaction logs are ingested into a log service. Raw logs are stored short-term. A summarization pipeline (using a cheap LLM) periodically compresses logs into structured insights stored in the vector DB. This prevents unbounded log growth while preserving searchable context. Agent interaction logs are ingested into a log service. Raw logs are stored short-term. A summarization pipeline (using a cheap LLM) periodically compresses logs into structured insights stored in the vector DB. This prevents unbounded log growth while preserving searchable context.
@@ -189,8 +189,8 @@ The gateway includes a cron scheduler for recurring tasks: log summarization run
**AD-12: Web search tool (DuckDuckGo MCP)** **AD-12: Web search tool (DuckDuckGo MCP)**
Agent sessions include a web search tool for information retrieval. DuckDuckGo via MCP server is the primary option (privacy-respecting, no API key required). Falls back to other search MCP providers if configured. Registered as a standard MCP tool available to all agent sessions. Agent sessions include a web search tool for information retrieval. DuckDuckGo via MCP server is the primary option (privacy-respecting, no API key required). Falls back to other search MCP providers if configured. Registered as a standard MCP tool available to all agent sessions.
**AD-13: Design system from @mosaic/design-tokens** **AD-13: Design system from @mosaicstack/design-tokens**
The web dashboard uses the Mosaic Stack design system established in `mosaic-stack-website`. The `@mosaic/design-tokens` package provides CSS custom properties, Tailwind preset, and TS color/font/radius exports. Dark theme default with light theme support. Fonts: Outfit (sans), Fira Code (mono). Color palette: deep blue-grays with blue/purple/teal accents. The web dashboard uses the Mosaic Stack design system established in `mosaic-stack-website`. The `@mosaicstack/design-tokens` package provides CSS custom properties, Tailwind preset, and TS color/font/radius exports. Dark theme default with light theme support. Fonts: Outfit (sans), Fira Code (mono). Color palette: deep blue-grays with blue/purple/teal accents.
**AD-14: Multi-tier deployment readiness** **AD-14: Multi-tier deployment readiness**
Code is structured assuming eventual multi-node deployment with dedicated roles (gateway nodes, agent worker nodes, brain/DB nodes). Packages communicate via well-defined APIs (HTTP/WS/MCP), not in-process calls where avoidable. Service boundaries are clean: gateway is stateless (state in PG/Valkey), agent pool can scale independently, brain is a separate service. v0.1.0 runs single-node; the architecture doesn't fight horizontal scaling later. Code is structured assuming eventual multi-node deployment with dedicated roles (gateway nodes, agent worker nodes, brain/DB nodes). Packages communicate via well-defined APIs (HTTP/WS/MCP), not in-process calls where avoidable. Service boundaries are clean: gateway is stateless (state in PG/Valkey), agent pool can scale independently, brain is a separate service. v0.1.0 runs single-node; the architecture doesn't fight horizontal scaling later.
@@ -205,25 +205,25 @@ Code is structured assuming eventual multi-node deployment with dedicated roles
mosaic-mono-v1/ mosaic-mono-v1/
├── apps/ ├── apps/
│ ├── web/ Next.js 16 web dashboard │ ├── web/ Next.js 16 web dashboard
│ └── gateway/ @mosaic/gateway — NestJS API + WebSocket │ └── gateway/ @mosaicstack/gateway — NestJS API + WebSocket
├── packages/ ├── packages/
│ ├── types/ @mosaic/types — shared type contracts │ ├── types/ @mosaicstack/types — shared type contracts
│ ├── brain/ @mosaic/brain — data layer (PG-backed) │ ├── brain/ @mosaicstack/brain — data layer (PG-backed)
│ ├── queue/ @mosaic/queue — Valkey task queue + MCP │ ├── queue/ @mosaicstack/queue — Valkey task queue + MCP
│ ├── coord/ @mosaic/coord — mission coordination │ ├── coord/ @mosaicstack/coord — mission coordination
│ ├── mosaic/ @mosaic/mosaic — install wizard │ ├── mosaic/ @mosaicstack/mosaic — install wizard
│ ├── prdy/ @mosaic/prdy — PRD wizard │ ├── prdy/ @mosaicstack/prdy — PRD wizard
│ ├── quality-rails/ @mosaic/quality-rails — code quality scaffolder │ ├── quality-rails/ @mosaicstack/quality-rails — code quality scaffolder
│ ├── cli/ @mosaic/cli — unified CLI │ ├── cli/ @mosaicstack/cli — unified CLI
│ ├── auth/ @mosaic/auth — BetterAuth config + SSO adapters │ ├── auth/ @mosaicstack/auth — BetterAuth config + SSO adapters
│ ├── db/ @mosaic/db — Drizzle schema, migrations, connection │ ├── db/ @mosaicstack/db — Drizzle schema, migrations, connection
│ ├── agent/ @mosaic/agent — Pi SDK integration, agent pool manager │ ├── agent/ @mosaicstack/agent — Pi SDK integration, agent pool manager
│ ├── memory/ @mosaic/memory — tiered memory + summarization service │ ├── memory/ @mosaicstack/memory — tiered memory + summarization service
│ ├── log/ @mosaic/log — agent log ingest + processing │ ├── log/ @mosaicstack/log — agent log ingest + processing
│ └── design-tokens/ @mosaic/design-tokens — CSS vars, Tailwind preset, colors │ └── design-tokens/ @mosaicstack/design-tokens — CSS vars, Tailwind preset, colors
├── plugins/ ├── plugins/
│ ├── discord/ @mosaic/discord-plugin — Discord channel │ ├── discord/ @mosaicstack/discord-plugin — Discord channel
│ └── telegram/ @mosaic/telegram-plugin — Telegram channel │ └── telegram/ @mosaicstack/telegram-plugin — Telegram channel
├── docker/ ├── docker/
│ ├── gateway.Dockerfile │ ├── gateway.Dockerfile
│ ├── web.Dockerfile │ ├── web.Dockerfile
@@ -244,7 +244,7 @@ mosaic-mono-v1/
### Package Responsibilities ### Package Responsibilities
#### `apps/gateway` — @mosaic/gateway (NEW — critical path) #### `apps/gateway` — @mosaicstack/gateway (NEW — critical path)
The central nervous system. All clients connect here. Built with NestJS (Fastify adapter). The central nervous system. All clients connect here. Built with NestJS (Fastify adapter).
@@ -303,7 +303,7 @@ Carried forward from jarvis-old with significant refactoring.
- User management (admin RBAC panel) - User management (admin RBAC panel)
- Auth pages (login, SSO redirect, registration) - Auth pages (login, SSO redirect, registration)
#### `packages/types` — @mosaic/types #### `packages/types` — @mosaicstack/types
Migrated from mosaic-mono-v0. Extended with: Migrated from mosaic-mono-v0. Extended with:
@@ -313,7 +313,7 @@ Migrated from mosaic-mono-v0. Extended with:
- Memory types (preference, insight, summary) - Memory types (preference, insight, summary)
- Plugin channel types (Discord, Telegram message mapping) - Plugin channel types (Discord, Telegram message mapping)
#### `packages/brain` — @mosaic/brain #### `packages/brain` — @mosaicstack/brain
Migrated from mosaic-mono-v0. **Storage backend changes from JSON to PostgreSQL.** Migrated from mosaic-mono-v0. **Storage backend changes from JSON to PostgreSQL.**
@@ -324,7 +324,7 @@ Migrated from mosaic-mono-v0. **Storage backend changes from JSON to PostgreSQL.
- New: computed endpoints (today, stale, stats, search, audit) run against PG - New: computed endpoints (today, stale, stats, search, audit) run against PG
- New: appreciation collection preserved for family use - New: appreciation collection preserved for family use
#### `packages/queue` — @mosaic/queue #### `packages/queue` — @mosaicstack/queue
Migrated from mosaic-mono-v0 with minimal changes. Migrated from mosaic-mono-v0 with minimal changes.
@@ -332,7 +332,7 @@ Migrated from mosaic-mono-v0 with minimal changes.
- MCP server with 8 tools - MCP server with 8 tools
- Used by gateway for agent task dispatch and coordination - Used by gateway for agent task dispatch and coordination
#### `packages/coord` — @mosaic/coord #### `packages/coord` — @mosaicstack/coord
Migrated from mosaic-mono-v0. Migrated from mosaic-mono-v0.
@@ -342,7 +342,7 @@ Migrated from mosaic-mono-v0.
- Continuation prompt generation - Continuation prompt generation
- Integration with gateway for mission-driven orchestration - Integration with gateway for mission-driven orchestration
#### `packages/db` — @mosaic/db (NEW) #### `packages/db` — @mosaicstack/db (NEW)
Shared database package. Shared database package.
@@ -351,7 +351,7 @@ Shared database package.
- Connection pool configuration - Connection pool configuration
- Shared by gateway, brain, auth, memory - Shared by gateway, brain, auth, memory
#### `packages/auth` — @mosaic/auth (NEW) #### `packages/auth` — @mosaicstack/auth (NEW)
Authentication and authorization. Authentication and authorization.
@@ -361,7 +361,7 @@ Authentication and authorization.
- API key generation for brain/MCP access - API key generation for brain/MCP access
- Session management middleware - Session management middleware
#### `packages/agent` — @mosaic/agent (NEW — critical path) #### `packages/agent` — @mosaicstack/agent (NEW — critical path)
Pi SDK integration layer. Pi SDK integration layer.
@@ -372,7 +372,7 @@ Pi SDK integration layer.
- Skill management — loads and configures Pi skills for agent sessions - Skill management — loads and configures Pi skills for agent sessions
- Session lifecycle — create, monitor, complete, fail, timeout - Session lifecycle — create, monitor, complete, fail, timeout
#### `packages/memory` — @mosaic/memory (NEW) #### `packages/memory` — @mosaicstack/memory (NEW)
Tiered memory system. Tiered memory system.
@@ -382,7 +382,7 @@ Tiered memory system.
- Summarization pipeline — compress raw logs into structured insights - Summarization pipeline — compress raw logs into structured insights
- Memory API — used by gateway and agent sessions - Memory API — used by gateway and agent sessions
#### `packages/log` — @mosaic/log (NEW) #### `packages/log` — @mosaicstack/log (NEW)
Agent log service. Agent log service.
@@ -392,7 +392,7 @@ Agent log service.
- Summarization trigger — invokes cheap LLM to compress aging logs - Summarization trigger — invokes cheap LLM to compress aging logs
- Retention policy — configurable TTLs per tier - Retention policy — configurable TTLs per tier
#### `packages/mosaic` — @mosaic/mosaic #### `packages/mosaic` — @mosaicstack/mosaic
Migrated from mosaic-mono-v0, updated for v1. Migrated from mosaic-mono-v0, updated for v1.
@@ -400,7 +400,7 @@ Migrated from mosaic-mono-v0, updated for v1.
- Detects existing installations, offers upgrade path - Detects existing installations, offers upgrade path
- Configures `~/.config/mosaic/` with guides, tools, runtime configs - Configures `~/.config/mosaic/` with guides, tools, runtime configs
#### `packages/prdy` — @mosaic/prdy #### `packages/prdy` — @mosaicstack/prdy
Migrated from mosaic-mono-v0. Migrated from mosaic-mono-v0.
@@ -408,7 +408,7 @@ Migrated from mosaic-mono-v0.
- Template-based PRD creation with Zod validation - Template-based PRD creation with Zod validation
- CLI integration via `mosaic prdy` - CLI integration via `mosaic prdy`
#### `packages/quality-rails` — @mosaic/quality-rails #### `packages/quality-rails` — @mosaicstack/quality-rails
Migrated from mosaic-mono-v0. Migrated from mosaic-mono-v0.
@@ -416,15 +416,15 @@ Migrated from mosaic-mono-v0.
- Generates ESLint, tsconfig, Woodpecker, husky, lint-staged configs - Generates ESLint, tsconfig, Woodpecker, husky, lint-staged configs
- Supports project types: monorepo, typescript-node, nextjs - Supports project types: monorepo, typescript-node, nextjs
#### `packages/cli` — @mosaic/cli #### `packages/cli` — @mosaicstack/cli
Migrated from mosaic-mono-v0, extended. Migrated from mosaic-mono-v0, extended.
- Unified `mosaic` binary - Unified `mosaic` binary
- Subcommands: `mosaic coord`, `mosaic prdy`, `mosaic queue`, `mosaic quality`, `mosaic gateway`, `mosaic brain` - Subcommands: `mosaic coord`, `mosaic prdy`, `mosaic queue`, `mosaic quality`, `mosaic gateway`, `mosaic brain`
- Plugin discovery for installed @mosaic/\* packages - Plugin discovery for installed @mosaicstack/\* packages
#### `plugins/discord` — @mosaic/discord-plugin (NEW — high priority) #### `plugins/discord` — @mosaicstack/discord-plugin (NEW — high priority)
Discord remote control channel. Architecture inspired by OpenClaw (https://github.com/openclaw/openclaw). Discord remote control channel. Architecture inspired by OpenClaw (https://github.com/openclaw/openclaw).
@@ -436,7 +436,7 @@ Discord remote control channel. Architecture inspired by OpenClaw (https://githu
- Bot pairing and permission management (Discord user → Mosaic user mapping) - Bot pairing and permission management (Discord user → Mosaic user mapping)
- DM support for private conversations - DM support for private conversations
#### `plugins/telegram` — @mosaic/telegram-plugin (NEW) #### `plugins/telegram` — @mosaicstack/telegram-plugin (NEW)
Telegram remote control channel. Telegram remote control channel.
@@ -547,7 +547,7 @@ Telegram remote control channel.
- WebSocket hub — real-time updates for chat, agent status, notifications - WebSocket hub — real-time updates for chat, agent status, notifications
- Rate limiting and request validation - Rate limiting and request validation
### FR-3: Agent Pool (@mosaic/agent) ### FR-3: Agent Pool (@mosaicstack/agent)
- Manage concurrent Pi SDK sessions - Manage concurrent Pi SDK sessions
- Provider configuration: API key management, endpoint URLs, model lists - Provider configuration: API key management, endpoint URLs, model lists
@@ -582,7 +582,7 @@ Telegram remote control channel.
- Mission CRUD (linked to project and PRD) - Mission CRUD (linked to project and PRD)
- Mission tasks with phases, dependencies, ordering - Mission tasks with phases, dependencies, ordering
- Mission summary with computed progress - Mission summary with computed progress
- Mission coordination via @mosaic/coord - Mission coordination via @mosaicstack/coord
- Active mission dashboard in web UI - Active mission dashboard in web UI
### FR-7: Memory System ### FR-7: Memory System
@@ -844,7 +844,7 @@ Telegram remote control channel.
- [ ] Database migrations run automatically on first start - [ ] Database migrations run automatically on first start
- [ ] `.env.example` documents all required configuration - [ ] `.env.example` documents all required configuration
### AC-11: @mosaic/\* Packages ### AC-11: @mosaicstack/\* Packages
- [ ] All 7 migrated packages build, pass tests, and integrate with gateway - [ ] All 7 migrated packages build, pass tests, and integrate with gateway
- [ ] `mosaic` CLI provides subcommands for each package - [ ] `mosaic` CLI provides subcommands for each package
@@ -870,7 +870,7 @@ Telegram remote control channel.
| Risk | Likelihood | Impact | Mitigation | | Risk | Likelihood | Impact | Mitigation |
| -------------------------------------------------- | ---------- | ------ | ---------------------------------------------------------------------------------------- | | -------------------------------------------------- | ---------- | ------ | ---------------------------------------------------------------------------------------- |
| Pi SDK API instability (pre-1.0) | Medium | High | Pin version, abstract behind @mosaic/agent interface | | Pi SDK API instability (pre-1.0) | Medium | High | Pin version, abstract behind @mosaicstack/agent interface |
| Brain PG migration complexity | Medium | Medium | Preserve Brain REST/MCP API contract; only storage changes | | Brain PG migration complexity | Medium | Medium | Preserve Brain REST/MCP API contract; only storage changes |
| Discord plugin complexity (OpenClaw has ~60 files) | Medium | Medium | Start minimal (DM + mention in channel), single-guild only; expand iteratively post-beta | | Discord plugin complexity (OpenClaw has ~60 files) | Medium | Medium | Start minimal (DM + mention in channel), single-guild only; expand iteratively post-beta |
| LLM provider subscription auth varies by provider | Medium | Medium | Abstract behind provider interface; implement per-provider adapters | | LLM provider subscription auth varies by provider | Medium | Medium | Abstract behind provider interface; implement per-provider adapters |
@@ -882,7 +882,7 @@ Telegram remote control channel.
| # | Question | Priority | Status | | # | Question | Priority | Status |
| --- | ------------------------------------------------------------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | --- | ------------------------------------------------------------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| 1 | Pi SDK version to pin for v0.1.0? | High | ✅ Resolved — Pin `@mariozechner/pi-coding-agent@~0.57.1` (current stable). Abstract behind `@mosaic/agent` interface to insulate from breaking changes. Bump deliberately after testing. | | 1 | Pi SDK version to pin for v0.1.0? | High | ✅ Resolved — Pin `@mariozechner/pi-coding-agent@~0.57.1` (current stable). Abstract behind `@mosaicstack/agent` interface to insulate from breaking changes. Bump deliberately after testing. |
| 2 | Authentik vs WorkOS vs Keycloak — which SSO provider to implement first? | Medium | ✅ Resolved — Authentik first (already in Jason's infrastructure) | | 2 | Authentik vs WorkOS vs Keycloak — which SSO provider to implement first? | Medium | ✅ Resolved — Authentik first (already in Jason's infrastructure) |
| 3 | Vector DB: pgvector sufficient or need Qdrant from the start? | Medium | ✅ Resolved — pgvector with VectorStore interface abstraction. Qdrant drops in later if needed. | | 3 | Vector DB: pgvector sufficient or need Qdrant from the start? | Medium | ✅ Resolved — pgvector with VectorStore interface abstraction. Qdrant drops in later if needed. |
| 4 | Summarization LLM: which model for log compression? | Medium | ✅ Resolved — Haiku-tier default with structured output guardrails, configurable via routing engine. | | 4 | Summarization LLM: which model for log compression? | Medium | ✅ Resolved — Haiku-tier default with structured output guardrails, configurable via routing engine. |
@@ -910,9 +910,9 @@ All work is **alpha** (< 0.1.0) until Jason approves 0.1.0 beta release.
### Phase 0: Foundation (v0.0.1) ### Phase 0: Foundation (v0.0.1)
- Scaffold monorepo (pnpm + turbo + tsconfig + eslint + vitest) - Scaffold monorepo (pnpm + turbo + tsconfig + eslint + vitest)
- `@mosaic/types` — migrate and extend from v0 - `@mosaicstack/types` — migrate and extend from v0
- `@mosaic/db` — Drizzle schema, PG connection, migrations - `@mosaicstack/db` — Drizzle schema, PG connection, migrations
- `@mosaic/auth` — BetterAuth setup with email/password - `@mosaicstack/auth` — BetterAuth setup with email/password
- OTEL foundation — `@opentelemetry/sdk-node` setup, SigNoz in docker-compose, trace propagation wired - OTEL foundation — `@opentelemetry/sdk-node` setup, SigNoz in docker-compose, trace propagation wired
- Docker Compose (PG 17 + Valkey + SigNoz) - Docker Compose (PG 17 + Valkey + SigNoz)
- CI pipeline (Woodpecker) - CI pipeline (Woodpecker)
@@ -921,19 +921,19 @@ All work is **alpha** (< 0.1.0) until Jason approves 0.1.0 beta release.
### Phase 1: Core API (v0.0.2) ### Phase 1: Core API (v0.0.2)
- `apps/gateway` — NestJS server (Fastify adapter), auth middleware, health endpoints - `apps/gateway` — NestJS server (Fastify adapter), auth middleware, health endpoints
- `@mosaic/brain` — migrate from v0, swap JSON store for PG via @mosaic/db - `@mosaicstack/brain` — migrate from v0, swap JSON store for PG via @mosaicstack/db
- `@mosaic/queue` — migrate from v0 (minimal changes) - `@mosaicstack/queue` — migrate from v0 (minimal changes)
- Gateway routes: conversations, tasks, projects, missions - Gateway routes: conversations, tasks, projects, missions
- WebSocket server for chat streaming - WebSocket server for chat streaming
- Basic agent dispatch (single provider, no routing) - Basic agent dispatch (single provider, no routing)
### Phase 2: Agent Layer (v0.0.3) ### Phase 2: Agent Layer (v0.0.3)
- `@mosaic/agent` — Pi SDK integration, agent pool manager - `@mosaicstack/agent` — Pi SDK integration, agent pool manager
- Multi-provider support (Anthropic + Ollama minimum) - Multi-provider support (Anthropic + Ollama minimum)
- Agent routing engine (cost/capability matrix) - Agent routing engine (cost/capability matrix)
- Tool registration (brain, queue, memory tools injected into agent sessions) - Tool registration (brain, queue, memory tools injected into agent sessions)
- `@mosaic/coord` — migrate from v0, integrate with gateway - `@mosaicstack/coord` — migrate from v0, integrate with gateway
### Phase 3: Web Dashboard (v0.0.4) ### Phase 3: Web Dashboard (v0.0.4)
@@ -946,25 +946,25 @@ All work is **alpha** (< 0.1.0) until Jason approves 0.1.0 beta release.
### Phase 4: Memory & Intelligence (v0.0.5) ### Phase 4: Memory & Intelligence (v0.0.5)
- `@mosaic/memory` — preference store, insight store, semantic search - `@mosaicstack/memory` — preference store, insight store, semantic search
- `@mosaic/log` — log ingest, parsing, tiered storage - `@mosaicstack/log` — log ingest, parsing, tiered storage
- Summarization pipeline - Summarization pipeline
- Memory integration into agent sessions - Memory integration into agent sessions
- Skill management interface (web UI + CLI) - Skill management interface (web UI + CLI)
### Phase 5: Remote Control (v0.0.6) ### Phase 5: Remote Control (v0.0.6)
- `@mosaic/discord-plugin` — Discord channel plugin - `@mosaicstack/discord-plugin` — Discord channel plugin
- `@mosaic/telegram-plugin` — Telegram channel plugin - `@mosaicstack/telegram-plugin` — Telegram channel plugin
- Plugin host in gateway - Plugin host in gateway
- SSO configuration (Authentik) - SSO configuration (Authentik)
### Phase 6: CLI & Tools (v0.0.7) ### Phase 6: CLI & Tools (v0.0.7)
- `@mosaic/cli` — unified CLI with all subcommands - `@mosaicstack/cli` — unified CLI with all subcommands
- `@mosaic/prdy` — migrate from v0 - `@mosaicstack/prdy` — migrate from v0
- `@mosaic/quality-rails` — migrate from v0 - `@mosaicstack/quality-rails` — migrate from v0
- `@mosaic/mosaic` — install wizard updated for v1 - `@mosaicstack/mosaic` — install wizard updated for v1
- Pi TUI integration (`mosaic tui`) - Pi TUI integration (`mosaic tui`)
### Phase 7: Polish & Beta (v0.0.8 → v0.1.0) ### Phase 7: Polish & Beta (v0.0.8 → v0.1.0)
@@ -982,11 +982,11 @@ All work is **alpha** (< 0.1.0) until Jason approves 0.1.0 beta release.
## Assumptions ## Assumptions
1. RESOLVED: **pgvector is sufficient** for semantic search at v0.1.0 scale (personal/family/team = thousands to low hundreds-of-thousands of vectors). `@mosaic/memory` defines a `VectorStore` interface with pgvector as the default adapter. The interface boundary makes Qdrant a drop-in migration if PG resource contention or scale demands it later. Zero additional infrastructure for v0.1.0. Rationale: Reduces ops burden; pgvector HNSW indexes are fast at this scale; interface abstraction costs almost nothing now. 1. RESOLVED: **pgvector is sufficient** for semantic search at v0.1.0 scale (personal/family/team = thousands to low hundreds-of-thousands of vectors). `@mosaicstack/memory` defines a `VectorStore` interface with pgvector as the default adapter. The interface boundary makes Qdrant a drop-in migration if PG resource contention or scale demands it later. Zero additional infrastructure for v0.1.0. Rationale: Reduces ops burden; pgvector HNSW indexes are fast at this scale; interface abstraction costs almost nothing now.
2. RESOLVED: **Authentik is the first SSO provider** — confirmed, already running in Jason's infrastructure. WorkOS and Keycloak adapters follow in Phase 7. 2. RESOLVED: **Authentik is the first SSO provider** — confirmed, already running in Jason's infrastructure. WorkOS and Keycloak adapters follow in Phase 7.
3. RESOLVED: **NestJS with Fastify adapter for the gateway.** The gateway's complexity (plugin host, agent pool, routing engine, WebSocket hub, MCP server, auth, brain/queue/memory/log integration) warrants NestJS's module system, DI, and guards. Fastify performance preserved via adapter. Aligns with USER.md stated stack ("NestJS API + Next.js web"). @mosaic/brain's Fastify code migrates into a NestJS module. 3. RESOLVED: **NestJS with Fastify adapter for the gateway.** The gateway's complexity (plugin host, agent pool, routing engine, WebSocket hub, MCP server, auth, brain/queue/memory/log integration) warrants NestJS's module system, DI, and guards. Fastify performance preserved via adapter. Aligns with USER.md stated stack ("NestJS API + Next.js web"). @mosaicstack/brain's Fastify code migrates into a NestJS module.
4. RESOLVED: **OpenTelemetry from Phase 0.** Wide-event logging is required from the start. OTEL auto-instrumentation for NestJS/PG/HTTP via `@opentelemetry/sdk-node`. SigNoz as the all-in-one OTEL backend (single Docker service). Every significant operation emits structured events with rich context. Custom spans for agent dispatch, routing decisions, memory writes. Rationale: Retrofitting observability is painful; baking it in from day one means consistent instrumentation across all services. 4. RESOLVED: **OpenTelemetry from Phase 0.** Wide-event logging is required from the start. OTEL auto-instrumentation for NestJS/PG/HTTP via `@opentelemetry/sdk-node`. SigNoz as the all-in-one OTEL backend (single Docker service). Every significant operation emits structured events with rich context. Custom spans for agent dispatch, routing decisions, memory writes. Rationale: Retrofitting observability is painful; baking it in from day one means consistent instrumentation across all services.
@@ -1002,4 +1002,4 @@ All work is **alpha** (< 0.1.0) until Jason approves 0.1.0 beta release.
10. ASSUMPTION: **Conversations and messages get their own PG tables** (not stored in brain's entity model). They follow a chat-specific schema with proper foreign keys to users and projects. Rationale: Chat has different access patterns (streaming, pagination, search) than brain entities. 10. ASSUMPTION: **Conversations and messages get their own PG tables** (not stored in brain's entity model). They follow a chat-specific schema with proper foreign keys to users and projects. Rationale: Chat has different access patterns (streaming, pagination, search) than brain entities.
11. RESOLVED: **Pi handles all target LLM providers natively.** Anthropic, OpenAI/Codex, Z.ai, Ollama, LM Studio, and llama.cpp are all supported via Pi's built-in providers or `models.json` configuration with `openai-completions` API type. No custom provider adapters needed in @mosaic/agent — only configuration management. 11. RESOLVED: **Pi handles all target LLM providers natively.** Anthropic, OpenAI/Codex, Z.ai, Ollama, LM Studio, and llama.cpp are all supported via Pi's built-in providers or `models.json` configuration with `openai-completions` API type. No custom provider adapters needed in @mosaicstack/agent — only configuration management.

View File

@@ -108,4 +108,4 @@ The web login page renders provider buttons from `NEXT_PUBLIC_*_ENABLED` flags.
## Failure mode ## Failure mode
Provider config is optional, but partial config is rejected at startup. If any provider-specific env var is present without the full required set, `@mosaic/auth` throws a bootstrap error with the missing keys instead of silently registering a broken provider. Provider config is optional, but partial config is rejected at startup. If any provider-specific env var is present without the full required set, `@mosaicstack/auth` throws a bootstrap error with the missing keys instead of silently registering a broken provider.

View File

@@ -91,7 +91,7 @@ packages/cli/src/tui/
```bash ```bash
cd /home/jwoltje/src/mosaic-mono-v1-worktrees/tui-improvements cd /home/jwoltje/src/mosaic-mono-v1-worktrees/tui-improvements
pnpm --filter @mosaic/cli exec tsx src/cli.ts tui pnpm --filter @mosaicstack/cli exec tsx src/cli.ts tui
# or after build: # or after build:
node packages/cli/dist/cli.js tui --gateway http://localhost:14242 node packages/cli/dist/cli.js tui --gateway http://localhost:14242
``` ```
@@ -99,7 +99,7 @@ node packages/cli/dist/cli.js tui --gateway http://localhost:14242
### Quality Gates ### Quality Gates
```bash ```bash
pnpm --filter @mosaic/cli typecheck && pnpm --filter @mosaic/cli lint pnpm --filter @mosaicstack/cli typecheck && pnpm --filter @mosaicstack/cli lint
pnpm --filter @mosaic/gateway typecheck && pnpm --filter @mosaic/gateway lint pnpm --filter @mosaicstack/gateway typecheck && pnpm --filter @mosaicstack/gateway lint
pnpm --filter @mosaic/types typecheck pnpm --filter @mosaicstack/types typecheck
``` ```

View File

@@ -1,30 +1,90 @@
# Tasks — Storage Abstraction Retrofit # Tasks — CLI Unification & E2E First-Run
> Single-writer: orchestrator only. Workers read but never modify. > Single-writer: orchestrator only. Workers read but never modify.
> >
> **Mission:** Decouple gateway from hardcoded Postgres/Valkey backends. Introduce interface-driven middleware so the gateway is backend-agnostic. Default to local tier (SQLite + JSON) for zero-dependency installs. > **Mission:** cli-unification-20260404
> > **Schema:** `| id | status | description | issue | agent | branch | depends_on | estimate | notes |`
> **`agent` column values:** `codex` | `sonnet` | `haiku` | `glm-5` | `opus` | `—` (auto/default) > **Status values:** `not-started` | `in-progress` | `done` | `blocked` | `failed` | `needs-qa`
> **Agent values:** `codex` | `sonnet` | `haiku` | `opus` | `glm-5` | `—` (auto)
| id | status | agent | description | tokens | ## Milestone 1 — Kill legacy @mosaicstack/cli (done)
| --------- | ----------- | ------ | ---------------------------------------------------------------- | ------ |
| SA-P1-001 | done | sonnet | Define QueueAdapter interface in packages/queue/src/types.ts | 3K | | id | status | description | issue | agent | branch | depends_on | estimate | notes |
| SA-P1-002 | done | sonnet | Define StorageAdapter interface in packages/storage/src/types.ts | 3K | | -------- | ------ | ----------------------------------------------------------------- | ----- | ----- | ---------------------------------- | ---------- | -------- | --------------------------- |
| SA-P1-003 | done | sonnet | Define MemoryAdapter interface in packages/memory/src/types.ts | 3K | | CU-01-01 | done | Delete packages/cli directory; update workspace + docs references | #398 | opus | chore/remove-cli-package-duplicate | — | 5K | Merged c39433c3. 6685 LOC. |
| SA-P1-004 | done | sonnet | Create adapter factory pattern + config types | 3K |
| SA-P2-001 | done | sonnet | Refactor @mosaic/queue: wrap ioredis as BullMQ adapter | 3K | ## Milestone 2 — Archive stale mission + scaffold new mission (done)
| SA-P2-002 | done | sonnet | Create @mosaic/storage: wrap Drizzle as Postgres adapter | 6K |
| SA-P2-003 | done | sonnet | Refactor @mosaic/memory: extract pgvector adapter | 4K | | id | status | description | issue | agent | branch | depends_on | estimate | notes |
| SA-P2-004 | done | sonnet | Update gateway modules to use factories + DI tokens | 5K | | -------- | ------ | ------------------------------------------------------------------ | ----- | ----- | ---------------------------- | ---------- | -------- | --------------------------------- |
| SA-P2-005 | done | opus | Verify Phase 2: all tests pass, typecheck clean | — | | CU-02-01 | done | Move stale MISSION-MANIFEST / TASKS / PRD-Harness to docs/archive/ | #399 | opus | docs/mission-cli-unification | CU-01-01 | 3K | Harness + storage missions done. |
| SA-P3-001 | done | sonnet | Implement local queue adapter: JSON file persistence | 5K | | CU-02-02 | done | Scaffold new MISSION-MANIFEST.md, TASKS.md, scratchpad | #399 | opus | docs/mission-cli-unification | CU-02-01 | 5K | This file + manifest + scratchpad |
| SA-P3-002 | done | sonnet | Implement SQLite storage adapter with better-sqlite3 | 8K | | CU-02-03 | done | PR review, merge, branch cleanup | #399 | opus | docs/mission-cli-unification | CU-02-02 | 2K | Merged as 6f15a84c |
| SA-P3-003 | done | sonnet | Implement keyword memory adapter — no vector dependency | 4K |
| SA-P3-004 | done | opus | Verify Phase 3: 42 new tests, 347 total passing | — | ## Milestone 3 — Gateway bootstrap token recovery
| SA-P4-001 | done | sonnet | MosaicConfig schema + loader with tier auto-detection | 6K |
| SA-P4-002 | done | sonnet | CLI: mosaic gateway init — interactive wizard | 4K | | id | status | description | issue | agent | branch | depends_on | estimate | notes |
| SA-P4-003 | done | sonnet | CLI: mosaic gateway start/stop/status lifecycle | 5K | | -------- | ------ | ---------------------------------------------------------------------------------------------- | ----- | ------ | ------ | ---------- | -------- | ----------------------------- |
| SA-P4-004 | done | opus | Verify Phase 4: 381 tests passing, 40/40 tasks clean | | | CU-03-01 | done | Implementation plan for BetterAuth-cookie recovery flow (decision locked 2026-04-04) | — | opus | — | CU-02-03 | 4K | Design locked; plan-only task |
| SA-P5-001 | not-started | codex | Migration tooling: mosaic storage export/import | — | | CU-03-02 | done | Server: add recovery/rotate endpoint on apps/gateway/src/admin (gated by design from CU-03-01) | — | sonnet | — | CU-03-01 | 12K | |
| SA-P5-002 | not-started | codex | Docker Compose profiles: local vs team | — | | CU-03-03 | done | CLI: `mosaic gateway login` — interactive BetterAuth sign-in, persist session | — | sonnet | — | CU-03-02 | 10K | |
| SA-P5-003 | not-started | codex | Final verification + docs: README, architecture diagram | — | | CU-03-04 | done | CLI: `mosaic gateway config rotate-token` — mint new admin token via authenticated API | — | sonnet | — | CU-03-03 | 8K | |
| CU-03-05 | done | CLI: `mosaic gateway config recover-token` — execute the recovery flow from CU-03-01 | — | sonnet | — | CU-03-03 | 10K | |
| CU-03-06 | done | Install UX: fix the "user exists, no token" dead-end in runInstall bootstrapFirstUser path | — | sonnet | — | CU-03-05 | 8K | |
| CU-03-07 | done | Tests: integration tests for each recovery path (happy + error) | — | sonnet | — | CU-03-06 | 10K | |
| CU-03-08 | done | Code review + remediation | — | haiku | — | CU-03-07 | 4K | |
## Milestone 4 — `mosaic --help` alphabetize + grouping
| id | status | description | issue | agent | branch | depends_on | estimate | notes |
| -------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- | ------ | ------ | ---------- | -------- | ------------------------------- |
| CU-04-01 | done | Enable `configureHelp({ sortSubcommands: true })` on root program and each subgroup | — | sonnet | — | CU-02-03 | 3K | |
| CU-04-02 | done | Group commands into sections (Runtime, Gateway, Framework, Platform) in help output | — | sonnet | — | CU-04-01 | 5K | |
| CU-04-03 | done | Verify help snapshots render readably; update any docs with stale output | — | haiku | — | CU-04-02 | 3K | |
| CU-04-04 | done | Top-level `mosaic config` command — `show`, `get <key>`, `set <key> <val>`, `edit`, `path` — wraps packages/mosaic/src/config/config-service.ts (framework/agent config; distinct from `mosaic gateway config`) | — | sonnet | — | CU-02-03 | 10K | New scope (decision 2026-04-04) |
| CU-04-05 | done | Tests + code review for CU-04-04 | — | haiku | — | CU-04-04 | 4K | |
## Milestone 5 — Sub-package CLI surface
> Pattern: each sub-package exports `register<Name>Command(program: Command)` co-located with the library code (proven by `@mosaicstack/quality-rails`). Wire into `packages/mosaic/src/cli.ts`.
| id | status | description | issue | agent | branch | depends_on | estimate | notes |
| -------- | ------ | --------------------------------------------------------------------------------------------------------- | ----- | ------ | ------ | ---------- | -------- | ------------------- |
| CU-05-01 | done | `mosaic forge` — subcommands: `run`, `status`, `resume`, `personas list` | — | sonnet | — | CU-02-03 | 18K | User priority |
| CU-05-02 | done | `mosaic storage` — subcommands: `status`, `tier show`, `tier switch`, `export`, `import`, `migrate` | — | sonnet | — | CU-02-03 | 15K | |
| CU-05-03 | done | `mosaic queue` — subcommands: `list`, `stats`, `pause/resume`, `jobs tail`, `drain` | — | sonnet | — | CU-02-03 | 12K | |
| CU-05-04 | done | `mosaic memory` — subcommands: `search`, `stats`, `insights list`, `preferences list` | — | sonnet | — | CU-02-03 | 12K | |
| CU-05-05 | done | `mosaic brain` — subcommands: `projects list/create`, `missions list`, `tasks list`, `conversations list` | — | sonnet | — | CU-02-03 | 15K | |
| CU-05-06 | done | `mosaic auth` — subcommands: `users list/create/delete`, `sso list`, `sso test`, `sessions list` | — | sonnet | — | CU-03-03 | 15K | needs gateway login |
| CU-05-07 | done | `mosaic log` — subcommands: `tail`, `search`, `export`, `level <level>` | — | sonnet | — | CU-02-03 | 10K | |
| CU-05-08 | done | `mosaic macp` — subcommands: `tasks list`, `submit`, `gate`, `events tail` | — | sonnet | — | CU-02-03 | 12K | |
| CU-05-09 | done | Wire all eight `register<Name>Command` calls into packages/mosaic/src/cli.ts | — | haiku | — | CU-05-01…8 | 3K | |
| CU-05-10 | done | Integration test: `mosaic <cmd> --help` exits 0 for every new command | — | haiku | — | CU-05-09 | 5K | |
## Milestone 6 — `mosaic telemetry`
| id | status | description | issue | agent | branch | depends_on | estimate | notes |
| -------- | ------ | ------------------------------------------------------------------------------------------------- | ----- | ------ | ------ | ---------- | -------- | ---------------------------------------------- |
| CU-06-01 | done | Add `@mosaicstack/telemetry-client-js` as dependency of `@mosaicstack/mosaic` from Gitea registry | — | sonnet | — | CU-02-03 | 3K | |
| CU-06-02 | done | `mosaic telemetry local` — status, tail, Jaeger link (wraps existing apps/gateway/src/tracing.ts) | — | sonnet | — | CU-06-01 | 8K | |
| CU-06-03 | done | `mosaic telemetry` — status, opt-in, opt-out, test, upload (uses telemetry-client-js) | — | sonnet | — | CU-06-01 | 12K | Dry-run mode when server endpoint not yet live |
| CU-06-04 | done | Persistent consent state in mosaic config; disabled by default | — | sonnet | — | CU-06-03 | 5K | |
| CU-06-05 | done | Tests + code review | — | haiku | — | CU-06-04 | 5K | |
## Milestone 7 — Unified first-run UX
| id | status | description | issue | agent | branch | depends_on | estimate | notes |
| -------- | ------ | ---------------------------------------------------------------------------------------------- | ----- | ------ | ------ | ---------- | -------- | ----- |
| CU-07-01 | done | tools/install.sh: after npm install, hand off to `mosaic wizard` then `mosaic gateway install` | — | sonnet | — | CU-03-06 | 10K | |
| CU-07-02 | done | `mosaic wizard` and `mosaic gateway install` coordination: shared state, no duplicate prompts | — | sonnet | — | CU-07-01 | 12K | |
| CU-07-03 | done | Post-install verification step: "gateway healthy, tui connects, admin token on file" | — | sonnet | — | CU-07-02 | 8K | |
| CU-07-04 | done | End-to-end test on a clean container from scratch | — | haiku | — | CU-07-03 | 8K | |
## Milestone 8 — Docs + release
| id | status | description | issue | agent | branch | depends_on | estimate | notes |
| -------- | ------ | ---------------------------------------------------------------------- | ----- | ------ | ------ | ---------- | -------- | ----- |
| CU-08-01 | done | Update README.md with new command tree, install flow, and feature list | — | sonnet | — | CU-07-04 | 8K | |
| CU-08-02 | done | Update docs/guides/user-guide.md with all new sub-package commands | — | sonnet | — | CU-08-01 | 10K | |
| CU-08-03 | done | Version bump `@mosaicstack/mosaic`, publish to Gitea registry | — | opus | — | CU-08-02 | 3K | |
| CU-08-04 | done | Release notes, tag `v0.1.0-rc.N`, publish release on Gitea | — | opus | — | CU-08-03 | 3K | |

View File

@@ -0,0 +1,70 @@
# Mission Manifest — Harness Foundation
> Persistent document tracking full mission scope, status, and session history.
> Updated by the orchestrator at each phase transition and milestone completion.
## Mission
**ID:** harness-20260321
**Statement:** Transform Mosaic Stack from a functional demo into a real multi-provider, task-routing AI harness. Persist all conversations, integrate frontier LLM providers (Anthropic, OpenAI, OpenRouter, Z.ai, Ollama), build granular task-aware agent routing, harden agent sessions, replace cron with BullMQ, and design the channel protocol for future Matrix/remote integration.
**Phase:** Complete
**Current Milestone:** All milestones done
**Progress:** 7 / 7 milestones
**Status:** complete
**Last Updated:** 2026-03-22 UTC
## Success Criteria
- [x] AC-1: Send messages in TUI → restart TUI → resume conversation → agent has full history and context
- [x] AC-2: Route a coding task to Claude Opus 4.6, a simple question to Haiku, a summarization to GLM-5 — all via granular routing rules
- [x] AC-3: Two users exist, User A's memory searches never return User B's data
- [x] AC-4: `/model claude-sonnet-4-6` in TUI switches the active model for subsequent messages
- [x] AC-5: `/agent coding-agent` in TUI switches to a different agent with different system prompt and tools
- [x] AC-6: BullMQ jobs execute on schedule, failures retry with backoff, admin can inspect via `/api/admin/jobs`
- [x] AC-7: Channel protocol document exists with Matrix integration points defined, reviewed, and approved
- [x] AC-8: Embeddings run on Ollama local models (no external API dependency for vector operations)
- [x] AC-9: All five providers (Anthropic, OpenAI, OpenRouter, Z.ai, Ollama) connect, list models, and complete chat requests
- [x] AC-10: Routing transparency — TUI displays which model was selected and the routing reason for each response
## Milestones
| # | ID | Name | Status | Branch | Issue | Started | Completed |
| --- | ------ | ---------------------------------- | ------ | ------ | --------- | ---------- | ---------- |
| 1 | ms-166 | Conversation Persistence & Context | done | — | #224#231 | 2026-03-21 | 2026-03-21 |
| 2 | ms-167 | Security & Isolation | done | — | #232#239 | 2026-03-21 | 2026-03-21 |
| 3 | ms-168 | Provider Integration | done | — | #240#251 | 2026-03-21 | 2026-03-22 |
| 4 | ms-169 | Agent Routing Engine | done | — | #252#264 | 2026-03-22 | 2026-03-22 |
| 5 | ms-170 | Agent Session Hardening | done | — | #265#272 | 2026-03-22 | 2026-03-22 |
| 6 | ms-171 | Job Queue Foundation | done | — | #273#280 | 2026-03-22 | 2026-03-22 |
| 7 | ms-172 | Channel Protocol Design | done | — | #281#288 | 2026-03-22 | 2026-03-22 |
## Deployment
| Target | URL | Method |
| -------------------- | --------- | -------------------------- |
| Docker Compose (dev) | localhost | docker compose up |
| Production | TBD | Docker Swarm via Portainer |
## Coordination
- **Primary Agent:** claude-opus-4-6
- **Sibling Agents:** sonnet (workers), haiku (verification)
- **Shared Contracts:** docs/PRD-Harness_Foundation.md, docs/TASKS.md
## Token Budget
| Metric | Value |
| ------ | ------ |
| Budget | — |
| Used | ~2.5M |
| Mode | normal |
## Session History
| Session | Runtime | Started | Duration | Ended Reason | Last Task |
| ------- | --------------- | ---------- | -------- | ------------ | ----------------- |
| 1 | claude-opus-4-6 | 2026-03-21 | ~6h | complete | M7-008 — all done |
## Scratchpad
Path: `docs/scratchpads/harness-20260321.md`

View File

@@ -0,0 +1,30 @@
# Tasks — Storage Abstraction Retrofit
> Single-writer: orchestrator only. Workers read but never modify.
>
> **Mission:** Decouple gateway from hardcoded Postgres/Valkey backends. Introduce interface-driven middleware so the gateway is backend-agnostic. Default to local tier (SQLite + JSON) for zero-dependency installs.
>
> **`agent` column values:** `codex` | `sonnet` | `haiku` | `glm-5` | `opus` | `—` (auto/default)
| id | status | agent | description | tokens |
| --------- | ----------- | ------ | ---------------------------------------------------------------- | ------ |
| SA-P1-001 | done | sonnet | Define QueueAdapter interface in packages/queue/src/types.ts | 3K |
| SA-P1-002 | done | sonnet | Define StorageAdapter interface in packages/storage/src/types.ts | 3K |
| SA-P1-003 | done | sonnet | Define MemoryAdapter interface in packages/memory/src/types.ts | 3K |
| SA-P1-004 | done | sonnet | Create adapter factory pattern + config types | 3K |
| SA-P2-001 | done | sonnet | Refactor @mosaicstack/queue: wrap ioredis as BullMQ adapter | 3K |
| SA-P2-002 | done | sonnet | Create @mosaicstack/storage: wrap Drizzle as Postgres adapter | 6K |
| SA-P2-003 | done | sonnet | Refactor @mosaicstack/memory: extract pgvector adapter | 4K |
| SA-P2-004 | done | sonnet | Update gateway modules to use factories + DI tokens | 5K |
| SA-P2-005 | done | opus | Verify Phase 2: all tests pass, typecheck clean | — |
| SA-P3-001 | done | sonnet | Implement local queue adapter: JSON file persistence | 5K |
| SA-P3-002 | done | sonnet | Implement SQLite storage adapter with better-sqlite3 | 8K |
| SA-P3-003 | done | sonnet | Implement keyword memory adapter — no vector dependency | 4K |
| SA-P3-004 | done | opus | Verify Phase 3: 42 new tests, 347 total passing | — |
| SA-P4-001 | done | sonnet | MosaicConfig schema + loader with tier auto-detection | 6K |
| SA-P4-002 | done | sonnet | CLI: mosaic gateway init — interactive wizard | 4K |
| SA-P4-003 | done | sonnet | CLI: mosaic gateway start/stop/status lifecycle | 5K |
| SA-P4-004 | done | opus | Verify Phase 4: 381 tests passing, 40/40 tasks clean | — |
| SA-P5-001 | not-started | codex | Migration tooling: mosaic storage export/import | — |
| SA-P5-002 | not-started | codex | Docker Compose profiles: local vs team | — |
| SA-P5-003 | not-started | codex | Final verification + docs: README, architecture diagram | — |

View File

@@ -12,9 +12,9 @@ context: Agents coupled directly to infrastructure backends, bypassing intended
Current packages are **direct adapters**, not **middleware**: Current packages are **direct adapters**, not **middleware**:
| Package | Current State | Intended Design | | Package | Current State | Intended Design |
|---------|---------------|-----------------| |---------|---------------|-----------------|
| `@mosaic/queue` | `ioredis` hardcoded | Interface → BullMQ OR local-files | | `@mosaicstack/queue` | `ioredis` hardcoded | Interface → BullMQ OR local-files |
| `@mosaic/db` | Drizzle + Postgres hardcoded | Interface → Postgres OR SQLite OR JSON/MD | | `@mosaicstack/db` | Drizzle + Postgres hardcoded | Interface → Postgres OR SQLite OR JSON/MD |
| `@mosaic/memory` | pgvector required | Interface → pgvector OR sqlite-vec OR keyword-search | | `@mosaicstack/memory` | pgvector required | Interface → pgvector OR sqlite-vec OR keyword-search |
## The gateway and TUI import these packages directly, which means they they're coupled to specific infrastructure. Users cannot run Mosaic Stack without Postgres + Valkey. ## The gateway and TUI import these packages directly, which means they they're coupled to specific infrastructure. Users cannot run Mosaic Stack without Postgres + Valkey.
@@ -46,15 +46,15 @@ The gateway imports the interface, not the backend. At startup it reads config a
```typescript ```typescript
// What should have happened: // What should have happened:
gateway/queue.service.ts @mosaic/queue (interface) queue.adapter.ts gateway/queue.service.ts @mosaicstack/queue (interface) queue.adapter.ts
// What actually happened: // What actually happened:
gateway/queue.service.ts @mosaic/queue ioredis (hardcoded) gateway/queue.service.ts @mosaicstack/queue ioredis (hardcoded)
``` ```
## The Current State Analysis ## The Current State Analysis
### `@mosaic/queue` (packages/queue/src/queue.ts) ### `@mosaicstack/queue` (packages/queue/src/queue.ts)
```typescript ```typescript
import Redis from 'ioredis'; // ← Direct import of backend import Redis from 'ioredis'; // ← Direct import of backend
@@ -68,7 +68,7 @@ export function createQueue(config?: QueueConfig): QueueHandle {
**Problem:** `ioredis` is imported in the package, not the adapter interface. Consumers cannot swap backends. **Problem:** `ioredis` is imported in the package, not the adapter interface. Consumers cannot swap backends.
### `@mosaic/db` (packages/db/src/client.ts) ### `@mosaicstack/db` (packages/db/src/client.ts)
```typescript ```typescript
import { drizzle, type PostgresJsDatabase } from 'drizzle-orm/postgres-js'; import { drizzle, type PostgresJsDatabase } from 'drizzle-orm/postgres-js';
@@ -84,10 +84,10 @@ export function createDb(url?: string): DbHandle {
**Problem:** Drizzle + Postgres is hardcoded. No SQLite, JSON, or file-based options. **Problem:** Drizzle + Postgres is hardcoded. No SQLite, JSON, or file-based options.
### `@mosaic/memory` (packages/memory/src/memory.ts) ### `@mosaicstack/memory` (packages/memory/src/memory.ts)
```typescript ```typescript
import type { Db } from '@mosaic/db'; // ← Depends on Drizzle/PG import type { Db } from '@mosaicstack/db'; // ← Depends on Drizzle/PG
export function createMemory(db: Db): Memory { export function createMemory(db: Db): Memory {
return { return {
@@ -97,7 +97,7 @@ export function createMemory(db: Db): Memory {
} }
``` ```
**Problem:** Memory package is tightly coupled to `@mosaic/db` (which is Postgres-only). No alternative storage backends. **Problem:** Memory package is tightly coupled to `@mosaicstack/db` (which is Postgres-only). No alternative storage backends.
## The Target Interfaces ## The Target Interfaces
@@ -361,7 +361,7 @@ Automated equivalent to Claude Code's "Dream: Memory Consolidation" cycle
**Implementation:** **Implementation:**
```typescript ```typescript
// In @mosaic/dream (new package) // In @mosaicstack/dream (new package)
export async function runDreamCycle(config: DreamConfig): Promise<DreamResult> { export async function runDreamCycle(config: DreamConfig): Promise<DreamResult> {
const memory = await loadMemoryAdapter(config.storage); const memory = await loadMemoryAdapter(config.storage);
@@ -420,7 +420,7 @@ export async function runDreamCycle(config: DreamConfig): Promise<DreamResult> {
2. Move Drizzle logic to `packages/storage/src/adapters/postgres.ts` 2. Move Drizzle logic to `packages/storage/src/adapters/postgres.ts`
3. Create SQLite adapter in `packages/storage/src/adapters/sqlite.ts` 3. Create SQLite adapter in `packages/storage/src/adapters/sqlite.ts`
4. Update gateway to use storage factory 4. Update gateway to use storage factory
5. Deprecate direct `@mosaic/db` imports 5. Deprecate direct `@mosaicstack/db` imports
#### 2.3 Memory Refactor #### 2.3 Memory Refactor
@@ -488,7 +488,7 @@ packages/
│ │ ├── types.ts # StorageAdapter interface │ │ ├── types.ts # StorageAdapter interface
│ │ ├── index.ts # Factory function │ │ ├── index.ts # Factory function
│ │ └── adapters/ │ │ └── adapters/
│ │ ├── postgres.ts # MOVED from @mosaic/db │ │ ├── postgres.ts # MOVED from @mosaicstack/db
│ │ ├── sqlite.ts # NEW: SQLite adapter │ │ ├── sqlite.ts # NEW: SQLite adapter
│ │ └── files.ts # NEW: JSON/MD adapter │ │ └── files.ts # NEW: JSON/MD adapter
│ └── package.json │ └── package.json
@@ -530,9 +530,9 @@ packages/
## Breaking Changes ## Breaking Changes
1. **`@mosaic/db`** → **`@mosaic/storage`** (with migration guide) 1. **`@mosaicstack/db`** → **`@mosaicstack/storage`** (with migration guide)
2. Direct `ioredis` imports → Use `@mosaic/queue` factory 2. Direct `ioredis` imports → Use `@mosaicstack/queue` factory
3. Direct `pgvector` queries → Use `@mosaic/memory` factory 3. Direct `pgvector` queries → Use `@mosaicstack/memory` factory
4. Gateway startup now requires storage config (defaults to local) 4. Gateway startup now requires storage config (defaults to local)
## Non-Breaking Migration Path ## Non-Breaking Migration Path

View File

@@ -61,7 +61,7 @@ pnpm install
### 4. Initialize the database ### 4. Initialize the database
```bash ```bash
pnpm --filter @mosaic/db db:migrate pnpm --filter @mosaicstack/db db:migrate
``` ```
### 5. Build all packages ### 5. Build all packages
@@ -73,7 +73,7 @@ pnpm build
### 6. Start the gateway ### 6. Start the gateway
```bash ```bash
pnpm --filter @mosaic/gateway dev pnpm --filter @mosaicstack/gateway dev
``` ```
Or for production (after build): Or for production (after build):
@@ -86,10 +86,10 @@ node apps/gateway/dist/main.js
```bash ```bash
# Development # Development
pnpm --filter @mosaic/web dev pnpm --filter @mosaicstack/web dev
# Production (after build) # Production (after build)
pnpm --filter @mosaic/web start pnpm --filter @mosaicstack/web start
``` ```
The web app runs on port `3000` by default. The web app runs on port `3000` by default.
@@ -157,7 +157,7 @@ pnpm build
### Step 5 — Run database migrations ### Step 5 — Run database migrations
```bash ```bash
pnpm --filter @mosaic/db db:migrate pnpm --filter @mosaicstack/db db:migrate
``` ```
### Step 6 — Start the gateway ### Step 6 — Start the gateway

View File

@@ -129,7 +129,7 @@ The gateway loads `.env` from the monorepo root via `dotenv` at startup
### 4. Push the Database Schema ### 4. Push the Database Schema
```bash ```bash
pnpm --filter @mosaic/db db:push pnpm --filter @mosaicstack/db db:push
``` ```
This applies the Drizzle schema directly to the database (development only; use This applies the Drizzle schema directly to the database (development only; use
@@ -138,7 +138,7 @@ migrations in production).
### 5. Start the Gateway ### 5. Start the Gateway
```bash ```bash
pnpm --filter @mosaic/gateway exec tsx src/main.ts pnpm --filter @mosaicstack/gateway exec tsx src/main.ts
``` ```
The gateway starts on port `14242` by default. The gateway starts on port `14242` by default.
@@ -146,7 +146,7 @@ The gateway starts on port `14242` by default.
### 6. Start the Web App ### 6. Start the Web App
```bash ```bash
pnpm --filter @mosaic/web dev pnpm --filter @mosaicstack/web dev
``` ```
The web app starts on port `3000` by default. The web app starts on port `3000` by default.
@@ -359,7 +359,7 @@ The `insights` table uses a `vector(1536)` column (pgvector) for semantic search
Apply schema changes directly to the dev database (no migration files created): Apply schema changes directly to the dev database (no migration files created):
```bash ```bash
pnpm --filter @mosaic/db db:push pnpm --filter @mosaicstack/db db:push
``` ```
### Generating Migrations ### Generating Migrations
@@ -367,7 +367,7 @@ pnpm --filter @mosaic/db db:push
For production-safe, versioned changes: For production-safe, versioned changes:
```bash ```bash
pnpm --filter @mosaic/db db:generate pnpm --filter @mosaicstack/db db:generate
``` ```
This creates a new SQL migration file in `packages/db/drizzle/`. This creates a new SQL migration file in `packages/db/drizzle/`.
@@ -375,7 +375,7 @@ This creates a new SQL migration file in `packages/db/drizzle/`.
### Running Migrations ### Running Migrations
```bash ```bash
pnpm --filter @mosaic/db db:migrate pnpm --filter @mosaicstack/db db:migrate
``` ```
### Drizzle Config ### Drizzle Config
@@ -387,8 +387,8 @@ directory are defined there.
1. Add the table definition to `packages/db/src/schema.ts`. 1. Add the table definition to `packages/db/src/schema.ts`.
2. Export it from `packages/db/src/index.ts`. 2. Export it from `packages/db/src/index.ts`.
3. Run `pnpm --filter @mosaic/db db:push` (dev) or 3. Run `pnpm --filter @mosaicstack/db db:push` (dev) or
`pnpm --filter @mosaic/db db:generate && pnpm --filter @mosaic/db db:migrate` `pnpm --filter @mosaicstack/db db:generate && pnpm --filter @mosaicstack/db db:migrate`
(production). (production).
--- ---

View File

@@ -8,6 +8,8 @@
4. [Tasks](#tasks) 4. [Tasks](#tasks)
5. [Settings](#settings) 5. [Settings](#settings)
6. [CLI Usage](#cli-usage) 6. [CLI Usage](#cli-usage)
7. [Sub-package Commands](#sub-package-commands)
8. [Telemetry](#telemetry)
--- ---
@@ -160,12 +162,18 @@ The `mosaic` CLI provides a terminal interface to the same gateway API.
### Installation ### Installation
The CLI ships as part of the `@mosaic/cli` package: Install via the Mosaic installer:
```bash ```bash
# From the monorepo root bash <(curl -fsSL https://git.mosaicstack.dev/mosaicstack/mosaic-stack/raw/branch/main/tools/install.sh)
pnpm --filter @mosaic/cli build ```
node packages/cli/dist/cli.js --help
The installer places the `mosaic` binary at `~/.npm-global/bin/mosaic`. Flags for
non-interactive use:
```bash
--yes # Accept all defaults
--no-auto-launch # Skip auto-launch of wizard after install
``` ```
Or if installed globally: Or if installed globally:
@@ -174,7 +182,60 @@ Or if installed globally:
mosaic --help mosaic --help
``` ```
### Signing In ### First-Run Wizard
After install the wizard launches automatically. You can re-run it at any time:
```bash
mosaic wizard
```
The wizard guides you through:
1. Gateway discovery or installation (`mosaic gateway install`)
2. Authentication (`mosaic gateway login`)
3. Post-install health check (`mosaic gateway verify`)
### Gateway Login and Token Recovery
```bash
# Authenticate with a gateway and save a session token
mosaic gateway login
# Verify the gateway is reachable and responding
mosaic gateway verify
# Rotate your current API token
mosaic gateway config rotate-token
# Recover a token via BetterAuth cookie (for accounts with no token)
mosaic gateway config recover-token
```
If you have an existing gateway account but lost your token (common after a
reinstall), use `mosaic gateway config recover-token` to retrieve a new one
without recreating your account.
### Configuration
```bash
# Print full config as JSON
mosaic config show
# Read a specific key
mosaic config get gateway.url
# Write a key
mosaic config set gateway.url http://localhost:14242
# Open config in $EDITOR
mosaic config edit
# Print config file path
mosaic config path
```
### Signing In (Legacy)
```bash ```bash
mosaic login --gateway http://localhost:14242 --email you@example.com mosaic login --gateway http://localhost:14242 --email you@example.com
@@ -236,3 +297,267 @@ mosaic prdy
# Quality rails scaffolder # Quality rails scaffolder
mosaic quality-rails mosaic quality-rails
``` ```
---
## Sub-package Commands
Each Mosaic sub-package exposes its full API surface through the `mosaic` CLI.
All sub-package commands accept `--help` for usage details.
### `mosaic auth` — User & Authentication Management
Manage gateway users, SSO providers, and active sessions.
```bash
# List all users
mosaic auth users list
# Create a new user
mosaic auth users create --email alice@example.com --name "Alice"
# Delete a user
mosaic auth users delete <userId>
# List configured SSO providers
mosaic auth sso
# List active sessions
mosaic auth sessions list
# Revoke a session
mosaic auth sessions revoke <sessionId>
```
### `mosaic brain` — Projects, Missions, Tasks, Conversations
Browse and manage the brain data layer (PostgreSQL-backed project/mission/task
store).
```bash
# List all projects
mosaic brain projects
# List missions for a project
mosaic brain missions --project <projectId>
# List tasks
mosaic brain tasks --status in-progress
# Browse conversations
mosaic brain conversations
mosaic brain conversations --project <projectId>
```
### `mosaic config` — CLI Configuration
Read and write the `mosaic` CLI configuration file.
```bash
# Show full config
mosaic config show
# Get a value
mosaic config get gateway.url
# Set a value
mosaic config set theme dark
# Open in editor
mosaic config edit
# Print file path
mosaic config path
```
### `mosaic forge` — AI Pipeline Management
Interact with the Forge multi-stage AI delivery pipeline (intake → board review
→ planning → coding → review → deploy).
```bash
# Start a new forge run for a brief
mosaic forge run --brief "Add dark mode toggle to settings"
# Check status of a running pipeline
mosaic forge status
mosaic forge status --run <runId>
# Resume a paused or interrupted run
mosaic forge resume --run <runId>
# List available personas (board review evaluators)
mosaic forge personas
```
### `mosaic gateway` — Gateway Lifecycle
Install, authenticate with, and verify the Mosaic gateway service.
```bash
# Install gateway (guided)
mosaic gateway install
# Verify gateway health post-install
mosaic gateway verify
# Log in and save token
mosaic gateway login
# Rotate API token
mosaic gateway config rotate-token
# Recover token via BetterAuth cookie (lost-token recovery)
mosaic gateway config recover-token
```
### `mosaic log` — Structured Log Access
Query and stream structured logs from the gateway.
```bash
# Stream live logs
mosaic log tail
mosaic log tail --level warn
# Search logs
mosaic log search "database connection"
mosaic log search --since 1h "error"
# Export logs to file
mosaic log export --output logs.json
mosaic log export --since 24h --level error --output errors.json
# Get/set log level
mosaic log level
mosaic log level debug
```
### `mosaic macp` — MACP Protocol
Interact with the MACP credential resolution, gate runner, and event bus.
```bash
# List MACP tasks
mosaic macp tasks
mosaic macp tasks --status pending
# Submit a new MACP task
mosaic macp submit --type credential-resolve --payload '{"key":"OPENAI_API_KEY"}'
# Run a gate check
mosaic macp gate --gate quality-check
# Stream MACP events
mosaic macp events
mosaic macp events --filter credential
```
### `mosaic memory` — Agent Memory
Query and inspect the agent memory layer.
```bash
# Semantic search over memory
mosaic memory search "previous decisions about auth"
# Show memory statistics
mosaic memory stats
# Generate memory insights report
mosaic memory insights
# View stored preferences
mosaic memory preferences
mosaic memory preferences --set editor=neovim
```
### `mosaic queue` — Task Queue (Valkey)
Manage the Valkey-backed task queue.
```bash
# List all queues
mosaic queue list
# Show queue statistics
mosaic queue stats
mosaic queue stats --queue agent-tasks
# Pause a queue
mosaic queue pause agent-tasks
# Resume a paused queue
mosaic queue resume agent-tasks
# List jobs in a queue
mosaic queue jobs agent-tasks
mosaic queue jobs agent-tasks --status failed
# Drain (empty) a queue
mosaic queue drain agent-tasks
```
### `mosaic storage` — Object Storage
Manage object storage tiers and data migrations.
```bash
# Show storage status and usage
mosaic storage status
# List available storage tiers
mosaic storage tier
# Export data from storage
mosaic storage export --bucket agent-artifacts --output ./artifacts.tar.gz
# Import data into storage
mosaic storage import --bucket agent-artifacts --input ./artifacts.tar.gz
# Migrate data between tiers
mosaic storage migrate --from hot --to cold --older-than 30d
```
---
## Telemetry
Mosaic includes an OpenTelemetry-based telemetry system. Local telemetry
(traces, metrics sent to Jaeger) is always available. Remote telemetry upload
requires explicit opt-in.
### Local Telemetry
```bash
# Show local OTEL collector / Jaeger status
mosaic telemetry local status
# Tail live OTEL spans
mosaic telemetry local tail
# Open Jaeger UI URL
mosaic telemetry local jaeger
```
### Remote Telemetry
Remote upload is a no-op (dry-run) until you opt in. Your consent state is
persisted in the config file.
```bash
# Show current consent state
mosaic telemetry status
# Opt in to remote telemetry
mosaic telemetry opt-in
# Opt out (data stays local)
mosaic telemetry opt-out
# Test telemetry pipeline without uploading
mosaic telemetry test
# Upload telemetry (requires opt-in; dry-run otherwise)
mosaic telemetry upload
```

View File

@@ -23,7 +23,7 @@
**Step 2: Run test to verify it fails** **Step 2: Run test to verify it fails**
Run: `pnpm --filter @mosaic/gateway test -- src/chat/__tests__/chat-security.test.ts src/__tests__/resource-ownership.test.ts` Run: `pnpm --filter @mosaicstack/gateway test -- src/chat/__tests__/chat-security.test.ts src/__tests__/resource-ownership.test.ts`
Expected: FAIL on current DTO/helper mismatch. Expected: FAIL on current DTO/helper mismatch.
@@ -56,7 +56,7 @@ Run the same command and require green.
**Step 3: Run targeted tests** **Step 3: Run targeted tests**
Run: `pnpm --filter @mosaic/gateway test -- src/chat/__tests__/chat-security.test.ts src/__tests__/resource-ownership.test.ts` Run: `pnpm --filter @mosaicstack/gateway test -- src/chat/__tests__/chat-security.test.ts src/__tests__/resource-ownership.test.ts`
Expected: PASS. Expected: PASS.

View File

@@ -26,7 +26,7 @@ This plan establishes the foundational architecture for these systems.
4. **Hot reload** — soft-restart the gateway to load new plugins/skills/commands without dropping connections 4. **Hot reload** — soft-restart the gateway to load new plugins/skills/commands without dropping connections
5. **Local primitives** — baseline commands that work even when disconnected from the gateway 5. **Local primitives** — baseline commands that work even when disconnected from the gateway
6. **Workspaces** — structured, git-backed, per-user/per-project filesystem layout with chroot isolation 6. **Workspaces** — structured, git-backed, per-user/per-project filesystem layout with chroot isolation
7. **Task orchestration** — unified `@mosaic/queue` layer bridging PG, workspace files, and Valkey for agent task assignment 7. **Task orchestration** — unified `@mosaicstack/queue` layer bridging PG, workspace files, and Valkey for agent task assignment
8. **Session garbage collection** — three-tier GC (session, sweep, full cold-start) across Valkey, PG, and filesystem 8. **Session garbage collection** — three-tier GC (session, sweep, full cold-start) across Valkey, PG, and filesystem
--- ---
@@ -220,7 +220,7 @@ Without `onUnload`, hot-reload is impossible — would leak listeners, duplicate
--- ---
## Type Contracts (`@mosaic/types`) ## Type Contracts (`@mosaicstack/types`)
### CommandDef — Gateway Command Manifest Entry ### CommandDef — Gateway Command Manifest Entry
@@ -407,7 +407,7 @@ The condensation step is a lightweight LLM call (cheap model, small context) tha
### Using Existing Queue Package ### Using Existing Queue Package
The `@mosaic/queue` package already provides `createQueue()` returning an ioredis handle on `redis://localhost:6380`. The `/system` storage will use the same Valkey instance directly via the redis handle — no queue semantics needed, just `SET`/`GET`/`DEL`/`EXPIRE`. The `@mosaicstack/queue` package already provides `createQueue()` returning an ioredis handle on `redis://localhost:6380`. The `/system` storage will use the same Valkey instance directly via the redis handle — no queue semantics needed, just `SET`/`GET`/`DEL`/`EXPIRE`.
--- ---
@@ -415,7 +415,7 @@ The `@mosaic/queue` package already provides `createQueue()` returning an ioredi
### Storage ### Storage
Postgres via `@mosaic/db`. The `preferences` table already exists in `packages/db/src/schema.ts` with the right shape: Postgres via `@mosaicstack/db`. The `preferences` table already exists in `packages/db/src/schema.ts` with the right shape:
```typescript ```typescript
// Existing schema — already has category + key + value JSONB // Existing schema — already has category + key + value JSONB
@@ -620,7 +620,7 @@ Aliases are resolved in `findCommand()` before manifest lookup.
### Phase 1: Types + Local Command Parsing (no gateway changes) ### Phase 1: Types + Local Command Parsing (no gateway changes)
1. Add `CommandDef`, `CommandManifest`, new socket events to `@mosaic/types` 1. Add `CommandDef`, `CommandManifest`, new socket events to `@mosaicstack/types`
2. Add `parseSlashCommand()` utility to `packages/cli` 2. Add `parseSlashCommand()` utility to `packages/cli`
3. Add `role: 'system'` to `Message` type, render system messages in `MessageList` 3. Add `role: 'system'` to `Message` type, render system messages in `MessageList`
4. Implement local-only commands: `/help`, `/stop`, `/cost`, `/status` (local state only) 4. Implement local-only commands: `/help`, `/stop`, `/cost`, `/status` (local state only)
@@ -639,7 +639,7 @@ Aliases are resolved in `findCommand()` before manifest lookup.
### Phase 3: Preferences & System Overrides ### Phase 3: Preferences & System Overrides
1. Create `user_preferences` table in `@mosaic/db`, Drizzle schema + migration 1. Create `user_preferences` table in `@mosaicstack/db`, Drizzle schema + migration
2. Create `PreferencesService` in gateway — CRUD + defaults + enforcement logic 2. Create `PreferencesService` in gateway — CRUD + defaults + enforcement logic
3. Implement `/preferences` command (REST-executed) 3. Implement `/preferences` command (REST-executed)
4. Implement `/system` command — Valkey storage, session-scoped 4. Implement `/system` command — Valkey storage, session-scoped
@@ -1159,7 +1159,7 @@ Additional tool sets needed for workspace workflows:
- **Docker/Portainer tools** — container management, deployment - **Docker/Portainer tools** — container management, deployment
- These are registered as additional `ToolDefinition[]` sets, same pattern as existing tools - These are registered as additional `ToolDefinition[]` sets, same pattern as existing tools
`@mosaic/prdy` already provides the PRD wizard tooling — the workspace structure gives it a canonical output location (`docs/PRD-<name>.md`). `@mosaicstack/prdy` already provides the PRD wizard tooling — the workspace structure gives it a canonical output location (`docs/PRD-<name>.md`).
### Task Queue & Orchestration ### Task Queue & Orchestration
@@ -1167,19 +1167,19 @@ Additional tool sets needed for workspace workflows:
There are currently two parallel systems for task management: There are currently two parallel systems for task management:
1. **`@mosaic/coord`** (file-based) — missions stored as `mission.json`, tasks in `TASKS.md`, file locks, session tracking, subprocess spawning. Built for single-machine orchestrator pattern. 1. **`@mosaicstack/coord`** (file-based) — missions stored as `mission.json`, tasks in `TASKS.md`, file locks, session tracking, subprocess spawning. Built for single-machine orchestrator pattern.
2. **PG tables** (`tasks`, `mission_tasks`, `missions`) — DB-backed CRUD with status, priority, assignee, project/mission FKs. Exposed via REST API and Brain repos. 2. **PG tables** (`tasks`, `mission_tasks`, `missions`) — DB-backed CRUD with status, priority, assignee, project/mission FKs. Exposed via REST API and Brain repos.
These are not connected. `@mosaic/coord` reads/writes files. The DB tables are managed via MissionsController. An agent using `coord_mission_status` gets file-based data; the dashboard shows DB data. These are not connected. `@mosaicstack/coord` reads/writes files. The DB tables are managed via MissionsController. An agent using `coord_mission_status` gets file-based data; the dashboard shows DB data.
#### Vision: `@mosaic/queue` as the Unified Task Layer #### Vision: `@mosaicstack/queue` as the Unified Task Layer
`@mosaic/queue` becomes the task orchestration service — not just a Valkey queue primitive, but the coordinator between agents, DB, and workspace files: `@mosaicstack/queue` becomes the task orchestration service — not just a Valkey queue primitive, but the coordinator between agents, DB, and workspace files:
``` ```
┌──────────────────────────────────────────────┐ ┌──────────────────────────────────────────────┐
│ @mosaic/queue │ │ @mosaicstack/queue │
│ (Task Orchestration Service) │ │ (Task Orchestration Service) │
│ │ │ │
│ ┌─────────────────┐ ┌──────────────────┐ │ │ ┌─────────────────┐ ┌──────────────────┐ │
@@ -1217,21 +1217,21 @@ These are not connected. `@mosaic/coord` reads/writes files. The DB tables are m
6. Agent completes → updates status via queue service → PG updated + file synced + lock released 6. Agent completes → updates status via queue service → PG updated + file synced + lock released
7. Gateway/orchestrator monitors progress, assigns next based on dependencies 7. Gateway/orchestrator monitors progress, assigns next based on dependencies
**Flatfile fallback:** If no PG configured, queue service writes to flatfiles in workspace (JSON task manifests). Preserves the `@mosaic/coord` file-based pattern for single-machine, no-DB deployments. **Flatfile fallback:** If no PG configured, queue service writes to flatfiles in workspace (JSON task manifests). Preserves the `@mosaicstack/coord` file-based pattern for single-machine, no-DB deployments.
**What this replaces:** **What this replaces:**
- `@mosaic/coord`'s file-only task tracking → unified DB+file via queue service - `@mosaicstack/coord`'s file-only task tracking → unified DB+file via queue service
- Direct PG CRUD for task status → routed through queue service for consistency - Direct PG CRUD for task status → routed through queue service for consistency
- Manual task assignment → queue-based distribution with agent claiming - Manual task assignment → queue-based distribution with agent claiming
**What this preserves:** **What this preserves:**
- `TASKS.md` file format — still the agent-readable working copy - `TASKS.md` file format — still the agent-readable working copy
- Mission structure from `@mosaic/coord` — creation, milestones, sessions - Mission structure from `@mosaicstack/coord` — creation, milestones, sessions
- `@mosaic/prdy` PRD workflow — writes to `docs/`, syncs metadata to DB - `@mosaicstack/prdy` PRD workflow — writes to `docs/`, syncs metadata to DB
> **Note:** This is a significant refactor of `@mosaic/coord` + `@mosaic/queue`. Warrants its own dedicated plan alongside the Gatekeeper plan. > **Note:** This is a significant refactor of `@mosaicstack/coord` + `@mosaicstack/queue`. Warrants its own dedicated plan alongside the Gatekeeper plan.
### Chroot Agent Sandboxing ### Chroot Agent Sandboxing
@@ -1271,7 +1271,7 @@ The following topics are significant enough to warrant their own dedicated plan
| Plan | Stub File | Scope | | Plan | Stub File | Scope |
| -------------------------- | -------------------------------------- | -------------------------------------------------------------------------------------------------- | | -------------------------- | -------------------------------------- | -------------------------------------------------------------------------------------------------- |
| **Gatekeeper Service** | `docs/plans/gatekeeper-service.md` | PR review/merge agent, quality gates, CI integration, trust boundary design | | **Gatekeeper Service** | `docs/plans/gatekeeper-service.md` | PR review/merge agent, quality gates, CI integration, trust boundary design |
| **Task Queue Unification** | `docs/plans/task-queue-unification.md` | `@mosaic/queue` refactor, `@mosaic/coord` consolidation, DB+file sync, flatfile fallback | | **Task Queue Unification** | `docs/plans/task-queue-unification.md` | `@mosaicstack/queue` refactor, `@mosaicstack/coord` consolidation, DB+file sync, flatfile fallback |
| **Chroot Sandboxing** | `docs/plans/chroot-sandboxing.md` | Chroot environment provisioning, capability management, Docker integration, namespace alternatives | | **Chroot Sandboxing** | `docs/plans/chroot-sandboxing.md` | Chroot environment provisioning, capability management, Docker integration, namespace alternatives |
--- ---
@@ -1447,7 +1447,7 @@ TUI requests fresh commands:manifest (reflects new provider availability)
### Implementation Notes ### Implementation Notes
- Gateway stores poll state in Valkey: `mosaic:auth:poll:<pollToken>` with 5-min TTL - Gateway stores poll state in Valkey: `mosaic:auth:poll:<pollToken>` with 5-min TTL
- `clipboardy` used for clipboard write in TUI (add as dep to `@mosaic/cli` if not already present) - `clipboardy` used for clipboard write in TUI (add as dep to `@mosaicstack/cli` if not already present)
- On success, gateway emits a fresh `commands:manifest` via socket (reflects provider now connected) - On success, gateway emits a fresh `commands:manifest` via socket (reflects provider now connected)
--- ---
@@ -1463,8 +1463,8 @@ mutable: boolean('mutable').notNull().default(true),
Generate and apply: Generate and apply:
```bash ```bash
pnpm --filter @mosaic/db db:generate # generates migration SQL pnpm --filter @mosaicstack/db db:generate # generates migration SQL
pnpm --filter @mosaic/db db:migrate # applies to PG pnpm --filter @mosaicstack/db db:migrate # applies to PG
``` ```
Platform enforcement keys (seeded with `mutable = false` by gateway `PreferencesService.onModuleInit()`): Platform enforcement keys (seeded with `mutable = false` by gateway `PreferencesService.onModuleInit()`):

View File

@@ -6,7 +6,7 @@
**Architecture:** The TUI gains a sidebar panel for conversation management (list/create/switch) fetched via REST from the gateway. A `useConversations` hook manages REST calls. A `useScrollableViewport` hook wraps the message list with virtual viewport logic. An app-level focus/mode state machine (`useAppMode`) controls which panel receives input. All new socket events for conversation listing use the existing REST API (`GET /api/conversations`). **Architecture:** The TUI gains a sidebar panel for conversation management (list/create/switch) fetched via REST from the gateway. A `useConversations` hook manages REST calls. A `useScrollableViewport` hook wraps the message list with virtual viewport logic. An app-level focus/mode state machine (`useAppMode`) controls which panel receives input. All new socket events for conversation listing use the existing REST API (`GET /api/conversations`).
**Tech Stack:** Ink 5, React 18, socket.io-client, fetch (for REST), @mosaic/types **Tech Stack:** Ink 5, React 18, socket.io-client, fetch (for REST), @mosaicstack/types
--- ---
@@ -125,7 +125,7 @@ export function useViewport(opts: UseViewportOptions): UseViewportReturn {
**Step 2: Typecheck** **Step 2: Typecheck**
Run: `pnpm --filter @mosaic/cli typecheck` Run: `pnpm --filter @mosaicstack/cli typecheck`
Expected: PASS Expected: PASS
**Step 3: Commit** **Step 3: Commit**
@@ -195,7 +195,7 @@ Note: Ink's `useInput` key object supports `pageUp`, `pageDown`. For Home/End, c
**Step 3: Typecheck and lint** **Step 3: Typecheck and lint**
Run: `pnpm --filter @mosaic/cli typecheck && pnpm --filter @mosaic/cli lint` Run: `pnpm --filter @mosaicstack/cli typecheck && pnpm --filter @mosaicstack/cli lint`
Expected: PASS Expected: PASS
**Step 4: Commit** **Step 4: Commit**
@@ -354,7 +354,7 @@ export function useConversations(opts: UseConversationsOptions): UseConversation
**Step 2: Typecheck** **Step 2: Typecheck**
Run: `pnpm --filter @mosaic/cli typecheck` Run: `pnpm --filter @mosaicstack/cli typecheck`
Expected: PASS Expected: PASS
**Step 3: Commit** **Step 3: Commit**
@@ -415,7 +415,7 @@ export function useAppMode(): UseAppModeReturn {
**Step 2: Typecheck** **Step 2: Typecheck**
Run: `pnpm --filter @mosaic/cli typecheck` Run: `pnpm --filter @mosaicstack/cli typecheck`
Expected: PASS Expected: PASS
**Step 3: Commit** **Step 3: Commit**
@@ -555,7 +555,7 @@ export function Sidebar({
**Step 2: Typecheck** **Step 2: Typecheck**
Run: `pnpm --filter @mosaic/cli typecheck` Run: `pnpm --filter @mosaicstack/cli typecheck`
Expected: PASS Expected: PASS
**Step 3: Commit** **Step 3: Commit**
@@ -636,7 +636,7 @@ const clearMessages = useCallback(() => {
**Step 3: Typecheck and lint** **Step 3: Typecheck and lint**
Run: `pnpm --filter @mosaic/cli typecheck && pnpm --filter @mosaic/cli lint` Run: `pnpm --filter @mosaicstack/cli typecheck && pnpm --filter @mosaicstack/cli lint`
Expected: PASS Expected: PASS
**Step 4: Commit** **Step 4: Commit**
@@ -739,7 +739,7 @@ In `bottom-bar.tsx`, add a hints line above the status lines (or integrate into
**Step 3: Typecheck and lint** **Step 3: Typecheck and lint**
Run: `pnpm --filter @mosaic/cli typecheck && pnpm --filter @mosaic/cli lint` Run: `pnpm --filter @mosaicstack/cli typecheck && pnpm --filter @mosaicstack/cli lint`
Expected: PASS Expected: PASS
**Step 4: Commit** **Step 4: Commit**
@@ -919,7 +919,7 @@ In `message-list.tsx`:
**Step 2: Typecheck and lint** **Step 2: Typecheck and lint**
Run: `pnpm --filter @mosaic/cli typecheck && pnpm --filter @mosaic/cli lint` Run: `pnpm --filter @mosaicstack/cli typecheck && pnpm --filter @mosaicstack/cli lint`
Expected: PASS Expected: PASS
**Step 3: Commit** **Step 3: Commit**
@@ -940,8 +940,8 @@ git commit -m "feat(cli): wire message search with highlight and viewport scroll
**Step 1: Full typecheck across all affected packages** **Step 1: Full typecheck across all affected packages**
```bash ```bash
pnpm --filter @mosaic/cli typecheck && pnpm --filter @mosaic/cli lint pnpm --filter @mosaicstack/cli typecheck && pnpm --filter @mosaicstack/cli lint
pnpm --filter @mosaic/types typecheck pnpm --filter @mosaicstack/types typecheck
``` ```
Expected: All PASS Expected: All PASS
@@ -951,7 +951,7 @@ Expected: All PASS
```bash ```bash
cd /home/jwoltje/src/mosaic-mono-v1-worktrees/tui-improvements cd /home/jwoltje/src/mosaic-mono-v1-worktrees/tui-improvements
docker compose up -d docker compose up -d
pnpm --filter @mosaic/cli exec tsx src/cli.ts tui pnpm --filter @mosaicstack/cli exec tsx src/cli.ts tui
``` ```
Verify: Verify:

View File

@@ -0,0 +1,193 @@
# Gateway Admin Token Recovery — Implementation Plan
**Mission:** `cli-unification-20260404`
**Task:** `CU-03-01` (planning only — no runtime code changes)
**Status:** Design locked (Session 1) — BetterAuth cookie-based recovery
---
## 1. Problem Statement
The gateway installer strands operators when the admin user exists but the admin
API token is missing. Concrete trigger:
- `~/.config/mosaic/gateway/meta.json` was deleted / regenerated.
- The installer was re-run after a previous successful bootstrap.
Flow today (`packages/mosaic/src/commands/gateway/install.ts:375-400`):
1. `bootstrapFirstUser` hits `GET /api/bootstrap/status`.
2. Server returns `needsSetup: false` because `users` count > 0.
3. Installer logs `Admin user already exists — skipping setup. (No admin token on file — sign in via the web UI to manage tokens.)` and returns.
4. The operator now has:
- No token in `meta.json`.
- No CLI path to mint a new one (`mosaic gateway <anything>` that needs the token fails).
- `POST /api/bootstrap/setup` locked out — it only runs when `users` count is zero (`apps/gateway/src/admin/bootstrap.controller.ts:34-37`).
- `POST /api/admin/tokens` gated by `AdminGuard` — requires either a bearer token (which they don't have) or a BetterAuth session (which they don't have in the CLI).
Dead end. The web UI is the only escape hatch today, and for headless installs even that may be inaccessible.
## 2. Design Summary
The BetterAuth session cookie is the authority. The operator runs
`mosaic gateway login` to sign in with email/password, which persists a session
cookie via `saveSession` (reusing `packages/mosaic/src/auth.ts`). With a valid
session, `mosaic gateway config recover-token` (stranded-operator entry point)
and `mosaic gateway config rotate-token` call the existing authenticated admin
endpoint `POST /api/admin/tokens` using the cookie, then persist the returned
plaintext to `meta.json` via `writeMeta`. **No new server endpoints are
required** — `AdminGuard` already accepts BetterAuth session cookies via its
`validateSession` path (`apps/gateway/src/admin/admin.guard.ts:90-120`).
## 3. Surface Contract
### 3.1 Server — no changes required
| Endpoint | Status | Notes |
| ------------------------------ | --------------- | ------------------------------------------------------------------------------------------------------------------------ |
| `POST /api/admin/tokens` | **Reuse as-is** | `admin-tokens.controller.ts:46-72`. Returns `{ id, label, scope, expiresAt, lastUsedAt, createdAt, plaintext }`. |
| `GET /api/admin/tokens` | **Reuse** | Useful for `mosaic gateway config tokens list` follow-on (out of scope for CU-03-01, but trivial once auth path exists). |
| `DELETE /api/admin/tokens/:id` | **Reuse** | Used by rotate flow for optional old-token revocation. |
| `POST /api/bootstrap/setup` | **Unchanged** | Remains first-user-only; not part of recovery. |
`AdminGuard.validateSession` takes BetterAuth cookies from `request.raw.headers`
via `fromNodeHeaders` and calls `auth.api.getSession({ headers })`. It also
enforces `role === 'admin'`. This is exactly the path the CLI will hit with
`Cookie: better-auth.session_token=...`.
**Confirmed feasible** during CU-03-01 investigation.
### 3.2 `mosaic gateway login`
Thin wrapper over the existing top-level `mosaic login`
(`packages/mosaic/src/cli.ts:42-76`) with gateway-specific defaults pulled from
`readMeta()`.
| Aspect | Behavior |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| Default gateway URL | `http://${meta.host}:${meta.port}` from `readMeta()`, fallback `http://localhost:14242`. |
| Flow | Prompt email + password -> `signIn()` -> `saveSession()`. |
| Persistence | `~/.mosaic/session.json` via existing `saveSession` (7-day expiry). |
| Decision | **Thin wrapper**, not alias. Rationale: defaults differ (reads `meta.json`), and discoverability under `mosaic gateway --help`. |
| Implementation | Share the sign-in logic by extracting a small `runLogin(gatewayUrl, email?, password?)` helper; both commands call it. |
### 3.3 `mosaic gateway config rotate-token`
| Aspect | Behavior |
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Precondition | Valid session (via `loadSession` + `validateSession`). On failure, print: "Not signed in — run `mosaic gateway login`" and exit non-zero. |
| Request | `POST ${gatewayUrl}/api/admin/tokens` with header `Cookie: <session>`, body `{ label: "CLI token (rotated YYYY-MM-DD)" }`. |
| On success | Read meta via `readMeta()`, set `meta.adminToken = plaintext`, `writeMeta(meta)`. Print the token banner (reuse `printAdminTokenBanner` shape). |
| Old token | **Optional `--revoke-old`** flag. When set and a previous `meta.adminToken` existed, call `DELETE /api/admin/tokens/:id` after rotation. Requires listing first to find the id; punt to CU-03-02 decision. Document as nice-to-have. |
| Exit codes | `0` success; `1` network error; `2` auth error; `3` server rejection. |
### 3.4 `mosaic gateway config recover-token`
Superset of `rotate-token` with an inline login nudge — the "stranded operator"
entry point.
| Step | Action |
| ---- | -------------------------------------------------------------------------------------------------------------------------------- |
| 1 | `readMeta()` — derive gateway URL. If meta is missing entirely, fall back to `--gateway` flag or default. |
| 2 | `loadSession(gatewayUrl)` then `validateSession`. If either fails, prompt inline: email + password -> `signIn` -> `saveSession`. |
| 3 | `POST /api/admin/tokens` with cookie, label `"Recovered via CLI YYYY-MM-DDTHH:mm"`. |
| 4 | Persist plaintext to `meta.json` via `writeMeta`. |
| 5 | Print the token banner and next-steps hints (e.g. `mosaic gateway status`). |
| 6 | Exit `0`. |
Key property: this command is **runnable with nothing but email+password in hand**.
It assumes the gateway is up but assumes no prior CLI session state.
### 3.5 File touch list (for CU-03-02..05 execution)
| File | Change |
| ----------------------------------------------------- | ------------------------------------------------------------------------------------------ |
| `packages/mosaic/src/commands/gateway.ts` | Register `login`, `config recover-token`, `config rotate-token` subcommands under `gw`. |
| `packages/mosaic/src/commands/gateway/config.ts` | Add `runRecoverToken`, `runRotateToken` handlers; export from module. |
| `packages/mosaic/src/commands/gateway/login.ts` (new) | Thin wrapper calling shared `runLogin` helper with meta-derived default URL. |
| `packages/mosaic/src/auth.ts` | No change expected. Possibly export a `requireSession(gatewayUrl)` helper (reuse pattern). |
| `packages/mosaic/src/commands/gateway/install.ts` | `bootstrapFirstUser` branch: "user exists, no token" -> offer recovery (see Section 4). |
## 4. Installer Fix (CU-03-06 preview)
Current stranding point is `install.ts:388-395`. The fix:
```
if (!status.needsSetup) {
if (meta.adminToken) {
// unchanged — happy path
} else {
// NEW: prompt "Admin exists but no token on file. Recover now? [Y/n]"
// If yes -> call runRecoverToken(gatewayUrl) inline (interactive):
// - prompt email + password
// - signIn -> saveSession
// - POST /api/admin/tokens
// - writeMeta(meta) with returned plaintext
// - print banner
// If no -> print the current stranded message but include:
// "Run `mosaic gateway config recover-token` when ready."
}
}
```
Shape notes (actual code lands in CU-03-06):
- Extract the recovery body so it can be called **both** from the standalone
command and from `bootstrapFirstUser` without duplicating prompts.
- Reuse the same `rl` readline interface already open in `bootstrapFirstUser`
for the inline prompts.
- Preserve non-interactive behavior: if `process.stdin.isTTY` is false, skip the
prompt and emit the "run recover-token" hint only.
## 5. Test Strategy (CU-03-07 scope)
### 5.1 Happy paths
| Command | Scenario | Expected |
| ------------------------------------- | ------------------------------------------------ | -------------------------------------------------------- |
| `mosaic gateway login` | Valid creds | `session.json` written, 7-day expiry, exit 0 |
| `mosaic gateway config rotate-token` | Valid session, server reachable | `meta.json` updated, banner printed, new token usable |
| `mosaic gateway config recover-token` | No session, valid creds, server reachable | Prompts for creds, writes session + meta, exit 0 |
| Installer inline recovery | Re-run after `meta.json` wipe, operator says yes | Meta restored, banner printed, no manual CLI step needed |
### 5.2 Error paths (must all produce actionable messages and non-zero exit)
| Failure | Expected handling |
| --------------------------------- | --------------------------------------------------------------------------------- |
| Invalid email/password | BetterAuth 401 surfaced as "Sign-in failed: <server message>", exit 2 |
| Expired stored session | Recover command silently re-prompts; rotate command exits 2 with "run login" hint |
| Gateway down / connection refused | "Could not reach gateway at <url>" exit 1 |
| Server rejects token creation | Print status + body excerpt, exit 3 |
| Meta file missing (recover) | Fall back to `--gateway` flag or default; warn that meta will be created |
| Non-admin user | `AdminGuard` 403 surfaced as "User is not an admin", exit 2 |
### 5.3 Integration test (recommended)
Spin up gateway in test harness, create admin user via `/api/bootstrap/setup`,
wipe `meta.json`, invoke `mosaic gateway config recover-token` programmatically,
assert new `meta.adminToken` works against `GET /api/admin/tokens`.
## 6. Risks & Open Questions
| # | Item | Severity | Mitigation |
| --- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------- |
| 1 | `AdminGuard.validateSession` calls `getSession` with `fromNodeHeaders(request.raw.headers)`. CLI sends `Cookie:` header only. Confirm BetterAuth reads from `Cookie`, not `Set-Cookie`. | Low | Confirmed — `mosaic login` + `mosaic tui` already use this flow successfully (`cli.ts:137-181`). |
| 2 | Session cookie local expiry (7d) vs BetterAuth server-side expiry may drift. | Low | `validateSession` hits `get-session`; handle 401 by re-prompting. |
| 3 | Label collision / unbounded token growth if operators run `recover-token` repeatedly. | Low | Include ISO timestamp in label. Optional `--revoke-old` in CU-03-02. Add `tokens list/prune` later. |
| 4 | `mosaic login` exists at top level and `mosaic gateway login` is a wrapper — risk of confusion. | Low | Document that `gateway login` is the preferred entry for gateway operators; top-level stays for compatibility. |
| 5 | `meta.json` write is not atomic. Crash between token creation and `writeMeta` leaves an orphan token server-side with no plaintext on disk. | Medium | Accept for now — re-running `recover-token` mints a fresh token. Document as known limitation. |
| 6 | Non-TTY installer runs (CI, headless provisioners) cannot prompt for creds interactively. | Medium | Installer inline recovery must skip prompt when `!process.stdin.isTTY`; emit the recover-token hint. |
| 7 | If `BETTER_AUTH_SECRET` rotates between login and recover, the session cookie is invalid — user must re-login. Acceptable but surface a clear error. | Low | Error handler maps 401 on recover -> "Session invalid; re-run `mosaic gateway login`". |
| 8 | No MFA today. When MFA lands, BetterAuth sign-in will return a challenge, not a cookie — recovery UX will need a second prompt step. | Future | Out of scope for this mission. Flag for future CLI work. |
## 7. Downstream Task Hooks
| Task | Scope |
| -------- | -------------------------------------------------------------------------- |
| CU-03-02 | Implement `mosaic gateway login` wrapper + shared `runLogin` extraction. |
| CU-03-03 | Implement `mosaic gateway config rotate-token`. |
| CU-03-04 | Implement `mosaic gateway config recover-token`. |
| CU-03-05 | Wire commands into `gateway.ts` registration, update `--help` copy. |
| CU-03-06 | Installer inline recovery hook in `bootstrapFirstUser`. |
| CU-03-07 | Tests per Section 5. |
| CU-03-08 | Docs: update gateway install README + operator runbook with recovery flow. |

View File

@@ -1,4 +1,4 @@
# Task Queue Unification — @mosaic/queue as Unified Orchestration Layer # Task Queue Unification — @mosaicstack/queue as Unified Orchestration Layer
> **Status:** Stub — deferred. Referenced from `2026-03-15-agent-platform-architecture.md` (Task Queue & Orchestration section). > **Status:** Stub — deferred. Referenced from `2026-03-15-agent-platform-architecture.md` (Task Queue & Orchestration section).
> Implement after Workspaces (P8-015) is complete. Requires workspace file structure to be in place. > Implement after Workspaces (P8-015) is complete. Requires workspace file structure to be in place.
@@ -12,7 +12,7 @@
Two disconnected task systems exist: Two disconnected task systems exist:
1. **`@mosaic/coord`** — file-based missions (`mission.json`, `TASKS.md`), file locks, subprocess spawning. Single-machine orchestrator pattern. 1. **`@mosaicstack/coord`** — file-based missions (`mission.json`, `TASKS.md`), file locks, subprocess spawning. Single-machine orchestrator pattern.
2. **PG tables** (`tasks`, `mission_tasks`, `missions`) — DB-backed CRUD, REST API, Brain repos. 2. **PG tables** (`tasks`, `mission_tasks`, `missions`) — DB-backed CRUD, REST API, Brain repos.
An agent using `coord_mission_status` gets file data. The dashboard shows DB data. They are never in sync. An agent using `coord_mission_status` gets file data. The dashboard shows DB data. They are never in sync.
@@ -21,22 +21,22 @@ An agent using `coord_mission_status` gets file data. The dashboard shows DB dat
## Vision ## Vision
`@mosaic/queue` becomes the unified task orchestration service bridging PG, workspace files, and Valkey: `@mosaicstack/queue` becomes the unified task orchestration service bridging PG, workspace files, and Valkey:
- DB is source of truth for structured state (status, assignees, timestamps) - DB is source of truth for structured state (status, assignees, timestamps)
- Workspace files (`TASKS.md`, PRDs) are working copies for agent interaction - Workspace files (`TASKS.md`, PRDs) are working copies for agent interaction
- Valkey handles real-time assignment queues and agent claim locks - Valkey handles real-time assignment queues and agent claim locks
- Flatfile fallback for no-DB single-machine deployments (preserves `@mosaic/coord` pattern) - Flatfile fallback for no-DB single-machine deployments (preserves `@mosaicstack/coord` pattern)
--- ---
## Scope (To Be Designed) ## Scope (To Be Designed)
- [ ] `@mosaic/queue` refactor — elevate from ioredis primitive to task orchestration service - [ ] `@mosaicstack/queue` refactor — elevate from ioredis primitive to task orchestration service
- [ ] DB ↔ file sync layer — writes to PG propagate to `TASKS.md`; file edits by agents sync back - [ ] DB ↔ file sync layer — writes to PG propagate to `TASKS.md`; file edits by agents sync back
- [ ] Task assignment queue — Valkey-backed RPUSH/BLPOP for agent task claiming - [ ] Task assignment queue — Valkey-backed RPUSH/BLPOP for agent task claiming
- [ ] Agent claim locks — `mosaic:queue:project:{id}:lock:{taskId}` with TTL - [ ] Agent claim locks — `mosaic:queue:project:{id}:lock:{taskId}` with TTL
- [ ] `@mosaic/coord` consolidation — file-based ops ported into queue service; `@mosaic/coord` becomes thin adapter or deprecated - [ ] `@mosaicstack/coord` consolidation — file-based ops ported into queue service; `@mosaicstack/coord` becomes thin adapter or deprecated
- [ ] Flatfile fallback — queue service writes JSON manifests when PG unavailable - [ ] Flatfile fallback — queue service writes JSON manifests when PG unavailable
- [ ] Status pub/sub — real-time task status updates via Valkey pub/sub - [ ] Status pub/sub — real-time task status updates via Valkey pub/sub
- [ ] Dependency resolution — block task assignment until dependencies are met - [ ] Dependency resolution — block task assignment until dependencies are met
@@ -56,5 +56,5 @@ An agent using `coord_mission_status` gets file data. The dashboard shows DB dat
## References ## References
- Original design context: `docs/plans/2026-03-15-agent-platform-architecture.md` → "Task Queue & Orchestration" section - Original design context: `docs/plans/2026-03-15-agent-platform-architecture.md` → "Task Queue & Orchestration" section
- Current `@mosaic/coord` implementation: `packages/coord/src/` - Current `@mosaicstack/coord` implementation: `packages/coord/src/`
- Current `@mosaic/queue` implementation: `packages/queue/src/` - Current `@mosaicstack/queue` implementation: `packages/queue/src/`

View File

@@ -18,7 +18,7 @@
| Command | Result | Evidence | | Command | Result | Evidence |
| --- | --- | --- | | --- | --- | --- |
| `pnpm --filter @mosaic/gateway test -- src/chat/__tests__/chat-security.test.ts src/__tests__/resource-ownership.test.ts` | pass | 3 test files passed, 20 tests passed | | `pnpm --filter @mosaicstack/gateway test -- src/chat/__tests__/chat-security.test.ts src/__tests__/resource-ownership.test.ts` | pass | 3 test files passed, 20 tests passed |
| `pnpm typecheck` | pass | turbo completed 18/18 package typecheck tasks | | `pnpm typecheck` | pass | turbo completed 18/18 package typecheck tasks |
| `pnpm lint` | pass | turbo completed 18/18 package lint tasks | | `pnpm lint` | pass | turbo completed 18/18 package lint tasks |
| `pnpm format:check` | pass | `All matched files use Prettier code style!` | | `pnpm format:check` | pass | `All matched files use Prettier code style!` |

View File

@@ -302,7 +302,7 @@ a fully open-source, self-contained AI development pipeline
framework. The Forge pipeline, MACP protocol, and credential framework. The Forge pipeline, MACP protocol, and credential
resolver together form a complete agentic development system. resolver together form a complete agentic development system.
Packaged correctly, this could be published as Packaged correctly, this could be published as
@mosaic/forge + @mosaic/macp — reusable by any team building @mosaicstack/forge + @mosaicstack/macp — reusable by any team building
AI-native development workflows. The mosaic-stack repo becomes AI-native development workflows. The mosaic-stack repo becomes
a reference implementation. Other organizations adopt the a reference implementation. Other organizations adopt the
protocol. MACP becomes a standard. protocol. MACP becomes a standard.
@@ -335,7 +335,7 @@ runtime; packages/forge becomes the brain. These should be
designed as separable concerns from the start. designed as separable concerns from the start.
DEFERRED OPPORTUNITIES: DEFERRED OPPORTUNITIES:
- Publish @mosaic/forge to npm (after consolidation stabilizes) - Publish @mosaicstack/forge to npm (after consolidation stabilizes)
- MACP as an open protocol spec with multiple implementations - MACP as an open protocol spec with multiple implementations
- Forge pipeline as a configurable product (enterprise personas, - Forge pipeline as a configurable product (enterprise personas,
custom stage sequences, SLA-based gate configuration) custom stage sequences, SLA-based gate configuration)
@@ -539,7 +539,7 @@ is listed in WP2's scope (`learning_capture.py` + `learning_recall.py`).
If OpenBrain's interface is undefined, why is it in WP2 either? If OpenBrain's interface is undefined, why is it in WP2 either?
Cut it from both WP2 and WP1. Make it a separate brief. Cut it from both WP2 and WP1. Make it a separate brief.
To the Moonshot: The "publish @mosaic/forge to npm" idea is To the Moonshot: The "publish @mosaicstack/forge to npm" idea is
premature. Publishing a package externally means committing to premature. Publishing a package externally means committing to
a public API and semver guarantees. Mosaic's pipeline is a public API and semver guarantees. Mosaic's pipeline is
actively evolving. Publishing now creates external consumers actively evolving. Publishing now creates external consumers
@@ -1223,7 +1223,7 @@ consideration. They are NOT in scope for this consolidation.
memory capture/recall. Requires a standalone brief once memory capture/recall. Requires a standalone brief once
the interface is defined. High long-term value. the interface is defined. High long-term value.
- @mosaic/forge external publication: After the consolidated - @mosaicstack/forge external publication: After the consolidated
package stabilizes, evaluate publishing as an open-source package stabilizes, evaluate publishing as an open-source
framework. Requires API freeze and semver commitment. framework. Requires API freeze and semver commitment.

Some files were not shown because too many files have changed in this diff Show More