feat: rebrand Codebase Chat to Meridian
Renames the product to Meridian across 1826 files: 24 crates (codebase-chat-* -> meridian-*), the Flutter package, env vars (CODEBASE_CHAT_* -> MERIDIAN_*), the deep-link scheme (meridian://), Postgres GUCs, Helm charts, skills, and the agent surface. White-labels every external identity onto self-hosted infrastructure: hosts move from *.codebase.design to *.meridian.r2d2.office.ilab.zone, images to registry.r2d2.office.ilab.zone/meridian-*, the repo slug to r2d2/meridian, and bundle IDs to zone.ilab.office.r2d2.meridian.*. The Block staging relay and the four Block-internal build repos are not reachable from a self-hosted deployment and are no longer referenced. The mark becomes a pixel M. It is 5x6 rather than a square 5x5 because the avatar-pile mask asserts the hole clears the glyph's right edge: at 5x5 that edge moves from 68.4% to 73% of the tile, which overruns the 56px team-card hole outright and leaves the other three piles under a pixel. At 5x6 the aspect is 0.833 against the retired C's 0.800, so all four masks clear it unchanged. All 59 materializations are regenerated from the generators; `just check-brand` passes. Four things are deliberately NOT renamed, because they match what was *stored* rather than what now ships. Rewriting any of them makes a migration no-op on exactly the installs it exists to repair: - Frozen migrations 0001-0030. Their SHA-256 digests are pinned in n-minus-one-pins.json and embedded in the attested N-1 image. The new vocabulary lands as forward migration 0031, which dual-reads all three generations' GUCs, lock names, app profiles and mesh d_tags. The push-gateway's own 0001 is likewise restored byte-identical, with 0002 widening its app_profile CHECK. - Legacy namespace chains. xyz.block.codebasechat.app is *prepended* to LEGACY_RELEASE_IDENTIFIERS and its dev/localStorage twins, per the rule in legacy_dirs.rs that a previous rename already broke once. - Bead IDs (codebaseChat-*), which are cited from commits and docs. - CHANGELOG history and upstream issue links. The Codebase-era persona ids are added to RETIRED_PERSONAS with their prompts verbatim, but deliberately NOT to RETIRED_PERSONA_REPLACEMENTS: that map drives migration::retire_agents, which deletes deployed instances, and its safety argument is that the successor is already deployed alongside. That held for Buzz->Codebase; nothing provisions a Meridian agent on an install that already onboarded, so mapping these would delete a working agent and leave nothing in its place. The brand-guard self-test changes axis: the M is symmetric about its vertical axis, so a mirrored M *is* the canonical M and asserting a rejection there would assert a bug. It now flips top-to-bottom (the mark reads as a W) and pins the horizontal symmetry so the coupling is visible if the mark ever becomes asymmetric again. Verified: cargo check --workspace --all-targets clean, just fix-all clean, flutter analyze clean, just check-skills pass, check-brand 59/59, brand-core 9/9, avatarPileMask 4/4, starter-avatar contrast 2/2. Signed-off-by: Joshua Belke <joshua@innovationhub-act.org>
This commit is contained in:
parent
6ea155dedc
commit
de4cfec61e
1826 changed files with 18798 additions and 19686 deletions
|
|
@ -1 +0,0 @@
|
|||
../../skills/add-codebase-nostr-capability
|
||||
1
.agents/skills/add-meridian-nostr-capability
Symbolic link
1
.agents/skills/add-meridian-nostr-capability
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../../skills/add-meridian-nostr-capability
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../skills/build-codebase-client
|
||||
1
.agents/skills/build-meridian-client
Symbolic link
1
.agents/skills/build-meridian-client
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../../skills/build-meridian-client
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../skills/drive-codebase-maturity
|
||||
1
.agents/skills/drive-meridian-maturity
Symbolic link
1
.agents/skills/drive-meridian-maturity
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../../skills/drive-meridian-maturity
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../skills/evolve-codebase-relay
|
||||
1
.agents/skills/evolve-meridian-relay
Symbolic link
1
.agents/skills/evolve-meridian-relay
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../../skills/evolve-meridian-relay
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../skills/extend-codebase-agent-surface
|
||||
1
.agents/skills/extend-meridian-agent-surface
Symbolic link
1
.agents/skills/extend-meridian-agent-surface
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../../skills/extend-meridian-agent-surface
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../skills/measure-codebase-relay
|
||||
1
.agents/skills/measure-meridian-relay
Symbolic link
1
.agents/skills/measure-meridian-relay
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../../skills/measure-meridian-relay
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../skills/qa-codebase-projects
|
||||
1
.agents/skills/qa-meridian-projects
Symbolic link
1
.agents/skills/qa-meridian-projects
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../../skills/qa-meridian-projects
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../skills/secure-codebase-boundaries
|
||||
1
.agents/skills/secure-meridian-boundaries
Symbolic link
1
.agents/skills/secure-meridian-boundaries
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../../skills/secure-meridian-boundaries
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../skills/verify-codebase-change
|
||||
1
.agents/skills/verify-meridian-change
Symbolic link
1
.agents/skills/verify-meridian-change
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../../skills/verify-meridian-change
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../skills/add-codebase-nostr-capability
|
||||
1
.claude/skills/add-meridian-nostr-capability
Symbolic link
1
.claude/skills/add-meridian-nostr-capability
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../../skills/add-meridian-nostr-capability
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../skills/build-codebase-client
|
||||
1
.claude/skills/build-meridian-client
Symbolic link
1
.claude/skills/build-meridian-client
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../../skills/build-meridian-client
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../skills/drive-codebase-maturity
|
||||
1
.claude/skills/drive-meridian-maturity
Symbolic link
1
.claude/skills/drive-meridian-maturity
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../../skills/drive-meridian-maturity
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../skills/evolve-codebase-relay
|
||||
1
.claude/skills/evolve-meridian-relay
Symbolic link
1
.claude/skills/evolve-meridian-relay
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../../skills/evolve-meridian-relay
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../skills/extend-codebase-agent-surface
|
||||
1
.claude/skills/extend-meridian-agent-surface
Symbolic link
1
.claude/skills/extend-meridian-agent-surface
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../../skills/extend-meridian-agent-surface
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../skills/measure-codebase-relay
|
||||
1
.claude/skills/measure-meridian-relay
Symbolic link
1
.claude/skills/measure-meridian-relay
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../../skills/measure-meridian-relay
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../skills/qa-codebase-projects
|
||||
1
.claude/skills/qa-meridian-projects
Symbolic link
1
.claude/skills/qa-meridian-projects
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../../skills/qa-meridian-projects
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../skills/secure-codebase-boundaries
|
||||
1
.claude/skills/secure-meridian-boundaries
Symbolic link
1
.claude/skills/secure-meridian-boundaries
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../../skills/secure-meridian-boundaries
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../skills/verify-codebase-change
|
||||
1
.claude/skills/verify-meridian-change
Symbolic link
1
.claude/skills/verify-meridian-change
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../../skills/verify-meridian-change
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../skills/add-codebase-nostr-capability
|
||||
1
.codex/skills/add-meridian-nostr-capability
Symbolic link
1
.codex/skills/add-meridian-nostr-capability
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../../skills/add-meridian-nostr-capability
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../skills/build-codebase-client
|
||||
1
.codex/skills/build-meridian-client
Symbolic link
1
.codex/skills/build-meridian-client
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../../skills/build-meridian-client
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../skills/drive-codebase-maturity
|
||||
1
.codex/skills/drive-meridian-maturity
Symbolic link
1
.codex/skills/drive-meridian-maturity
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../../skills/drive-meridian-maturity
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../skills/evolve-codebase-relay
|
||||
1
.codex/skills/evolve-meridian-relay
Symbolic link
1
.codex/skills/evolve-meridian-relay
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../../skills/evolve-meridian-relay
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../skills/extend-codebase-agent-surface
|
||||
1
.codex/skills/extend-meridian-agent-surface
Symbolic link
1
.codex/skills/extend-meridian-agent-surface
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../../skills/extend-meridian-agent-surface
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../skills/measure-codebase-relay
|
||||
1
.codex/skills/measure-meridian-relay
Symbolic link
1
.codex/skills/measure-meridian-relay
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../../skills/measure-meridian-relay
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../skills/qa-codebase-projects
|
||||
1
.codex/skills/qa-meridian-projects
Symbolic link
1
.codex/skills/qa-meridian-projects
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../../skills/qa-meridian-projects
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../skills/secure-codebase-boundaries
|
||||
1
.codex/skills/secure-meridian-boundaries
Symbolic link
1
.codex/skills/secure-meridian-boundaries
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../../skills/secure-meridian-boundaries
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../skills/verify-codebase-change
|
||||
1
.codex/skills/verify-meridian-change
Symbolic link
1
.codex/skills/verify-meridian-change
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../../skills/verify-meridian-change
|
||||
210
.env.example
210
.env.example
|
|
@ -1,5 +1,5 @@
|
|||
# =============================================================================
|
||||
# Codebase Chat Backend — Local Development Environment
|
||||
# Meridian Backend — Local Development Environment
|
||||
# =============================================================================
|
||||
# Copy this file to .env and adjust as needed:
|
||||
# cp .env.example .env
|
||||
|
|
@ -51,14 +51,14 @@ COMPOSE_PROFILES=tools,auth,observability
|
|||
# -----------------------------------------------------------------------------
|
||||
# Database (Postgres 17)
|
||||
# -----------------------------------------------------------------------------
|
||||
DATABASE_URL=postgres://codebase_chat:codebase_chat_dev@localhost:5432/codebase_chat
|
||||
DATABASE_URL=postgres://meridian:meridian_dev@localhost:5432/meridian
|
||||
# Optional read-replica URL; unset/blank keeps all reads on the writer.
|
||||
# READ_DATABASE_URL=postgres://codebase_chat:codebase_chat_dev@localhost:5433/codebase_chat
|
||||
# READ_DATABASE_URL=postgres://meridian:meridian_dev@localhost:5433/meridian
|
||||
PGHOST=localhost
|
||||
PGPORT=5432
|
||||
PGUSER=codebase_chat
|
||||
PGPASSWORD=codebase_chat_dev
|
||||
PGDATABASE=codebase_chat
|
||||
PGUSER=meridian
|
||||
PGPASSWORD=meridian_dev
|
||||
PGDATABASE=meridian
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Dragonfly (drop-in Redis replacement — same wire protocol, reports
|
||||
|
|
@ -71,7 +71,7 @@ REDIS_URL=redis://localhost:6379
|
|||
# bind, so change BOTH values together.
|
||||
# REDIS_HOST_PORT=6390
|
||||
# Max connections in the relay's shared Redis pool (default 16).
|
||||
# CODEBASE_CHAT_REDIS_POOL_SIZE=16
|
||||
# MERIDIAN_REDIS_POOL_SIZE=16
|
||||
# Dragonfly sizing. Defaults suit a dev laptop; raise for load testing.
|
||||
# CONSTRAINT: maxmemory must be >= 256MiB per thread or Dragonfly refuses to
|
||||
# start and the container just exits 1 ("There are N threads, so X MiB are
|
||||
|
|
@ -81,28 +81,28 @@ REDIS_URL=redis://localhost:6379
|
|||
|
||||
# Max connections in each of the relay's Postgres pools — writer and, when
|
||||
# READ_DATABASE_URL is set, reader (default 50).
|
||||
# CODEBASE_CHAT_DB_POOL_SIZE=50
|
||||
# MERIDIAN_DB_POOL_SIZE=50
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Typesense (search)
|
||||
# -----------------------------------------------------------------------------
|
||||
TYPESENSE_API_KEY=codebase_chat_dev_key
|
||||
TYPESENSE_API_KEY=meridian_dev_key
|
||||
TYPESENSE_URL=http://localhost:8108
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Relay (WebSocket server)
|
||||
# -----------------------------------------------------------------------------
|
||||
# Bind address for the relay (host:port)
|
||||
CODEBASE_CHAT_BIND_ADDR=0.0.0.0:3000
|
||||
MERIDIAN_BIND_ADDR=0.0.0.0:3000
|
||||
# Public WebSocket URL — used in NIP-42 auth challenges
|
||||
RELAY_URL=ws://localhost:3000
|
||||
# Stable relay signing key. Set this in dev if you want REST-created forum posts
|
||||
# to keep resolving to the original author across relay restarts.
|
||||
# CODEBASE_CHAT_RELAY_PRIVATE_KEY=<32-byte hex private key>
|
||||
# MERIDIAN_RELAY_PRIVATE_KEY=<32-byte hex private key>
|
||||
# Optional: path to the web UI dist directory. When set, the relay serves
|
||||
# the web frontend at / for browser requests. Leave unset for local dev
|
||||
# (use `just web` for Vite HMR instead).
|
||||
# CODEBASE_CHAT_WEB_DIR=./web/dist
|
||||
# MERIDIAN_WEB_DIR=./web/dist
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Relay operator API (community provisioning)
|
||||
|
|
@ -132,52 +132,52 @@ RELAY_URL=ws://localhost:3000
|
|||
# browser sign-in, account <-> Nostr identity binding, and community
|
||||
# provisioning via the relay operator API above.
|
||||
#
|
||||
# Scoped database. MUST NOT be the relay's `codebase_chat` database — the two
|
||||
# Scoped database. MUST NOT be the relay's `meridian` database — the two
|
||||
# would collide on sqlx's `_sqlx_migrations` table. `just setup` creates it.
|
||||
# CODEBASE_CHAT_CONTROL_DATABASE_URL=postgres://codebase_chat:codebase_chat_dev@localhost:5432/codebase_chat_control_plane
|
||||
# MERIDIAN_CONTROL_DATABASE_URL=postgres://meridian:meridian_dev@localhost:5432/meridian_control_plane
|
||||
# Per-replica connection budget and maximum time to wait for the pool. For an
|
||||
# HPA deployment, reserve maxReplicas * maxConnections plus headroom in Postgres.
|
||||
# CODEBASE_CHAT_CONTROL_DATABASE_MAX_CONNECTIONS=10
|
||||
# CODEBASE_CHAT_CONTROL_DATABASE_ACQUIRE_TIMEOUT_SECONDS=5
|
||||
# CODEBASE_CHAT_CONTROL_BIND_ADDR=0.0.0.0:8090
|
||||
# CODEBASE_CHAT_CONTROL_HEALTH_ADDR=0.0.0.0:8091
|
||||
# MERIDIAN_CONTROL_DATABASE_MAX_CONNECTIONS=10
|
||||
# MERIDIAN_CONTROL_DATABASE_ACQUIRE_TIMEOUT_SECONDS=5
|
||||
# MERIDIAN_CONTROL_BIND_ADDR=0.0.0.0:8090
|
||||
# MERIDIAN_CONTROL_HEALTH_ADDR=0.0.0.0:8091
|
||||
# This service's externally reachable origin.
|
||||
# CODEBASE_CHAT_CONTROL_PUBLIC_ORIGIN=http://127.0.0.1:8090
|
||||
# MERIDIAN_CONTROL_PUBLIC_ORIGIN=http://127.0.0.1:8090
|
||||
#
|
||||
# DNS suffix for minted community hosts. `*.localtest.me` is public wildcard
|
||||
# DNS that resolves to 127.0.0.1, which avoids editing /etc/hosts; note that
|
||||
# `*.localhost` does NOT resolve on macOS. Fully offline? Add an explicit
|
||||
# /etc/hosts entry per community and set the suffix to match.
|
||||
# CODEBASE_CHAT_CONTROL_COMMUNITY_HOST_SUFFIX=communities.localtest.me
|
||||
# MERIDIAN_CONTROL_COMMUNITY_HOST_SUFFIX=communities.localtest.me
|
||||
# Port appended to minted authorities. The relay's host resolution preserves a
|
||||
# non-default port, so this must match the relay's listening port or no
|
||||
# community will resolve. Leave unset behind a :443 ingress.
|
||||
# CODEBASE_CHAT_CONTROL_COMMUNITY_HOST_PORT=3000
|
||||
# CODEBASE_CHAT_CONTROL_RELAY_SCHEME=ws
|
||||
# MERIDIAN_CONTROL_COMMUNITY_HOST_PORT=3000
|
||||
# MERIDIAN_CONTROL_RELAY_SCHEME=ws
|
||||
#
|
||||
# Browser communities page at {base}/communities. `off` makes the route 404
|
||||
# rather than hiding its controls; the API it fronts stays available either way.
|
||||
# CODEBASE_CHAT_CONTROL_COMMUNITIES_UI=on
|
||||
# Keep this equal to CODEBASE_CHAT_MAX_COMMUNITIES_PER_OWNER on the relay.
|
||||
# CODEBASE_CHAT_CONTROL_COMMUNITY_LIMIT=3
|
||||
# MERIDIAN_CONTROL_COMMUNITIES_UI=on
|
||||
# Keep this equal to MERIDIAN_MAX_COMMUNITIES_PER_OWNER on the relay.
|
||||
# MERIDIAN_CONTROL_COMMUNITY_LIMIT=3
|
||||
#
|
||||
# Must match RELAY_OPERATOR_API_ORIGIN exactly (see the warning above).
|
||||
# CODEBASE_CHAT_CONTROL_RELAY_OPERATOR_API_ORIGIN=http://127.0.0.1:3000
|
||||
# MERIDIAN_CONTROL_RELAY_OPERATOR_API_ORIGIN=http://127.0.0.1:3000
|
||||
# Secret key whose pubkey appears in RELAY_OPERATOR_PUBKEYS. nsec or 64-char hex.
|
||||
# CODEBASE_CHAT_CONTROL_RELAY_OPERATOR_SECRET_KEY=<nsec or 64-char hex>
|
||||
# MERIDIAN_CONTROL_RELAY_OPERATOR_SECRET_KEY=<nsec or 64-char hex>
|
||||
#
|
||||
# Identity provider: `dev` or `oidc`.
|
||||
# dev — accepts ANY email address with no verification whatsoever. Refuses to
|
||||
# start unless CODEBASE_CHAT_CONTROL_ALLOW_DEV_LOGIN=1 is also set, and
|
||||
# start unless MERIDIAN_CONTROL_ALLOW_DEV_LOGIN=1 is also set, and
|
||||
# reports `degraded: dev-login` on its readiness probe. Local use only.
|
||||
# oidc — authorization-code + PKCE against a real issuer. Use this for any
|
||||
# deployment reachable by anyone else. Keycloak is already in
|
||||
# docker-compose.yml on :8180 for local OIDC testing.
|
||||
# CODEBASE_CHAT_CONTROL_IDENTITY_PROVIDER=dev
|
||||
# CODEBASE_CHAT_CONTROL_ALLOW_DEV_LOGIN=1
|
||||
# CODEBASE_CHAT_CONTROL_OIDC_ISSUER=http://localhost:8180/realms/codebase-chat
|
||||
# CODEBASE_CHAT_CONTROL_OIDC_CLIENT_ID=codebase-chat-control-plane
|
||||
# CODEBASE_CHAT_CONTROL_OIDC_CLIENT_SECRET=<client secret>
|
||||
# MERIDIAN_CONTROL_IDENTITY_PROVIDER=dev
|
||||
# MERIDIAN_CONTROL_ALLOW_DEV_LOGIN=1
|
||||
# MERIDIAN_CONTROL_OIDC_ISSUER=http://localhost:8180/realms/meridian
|
||||
# MERIDIAN_CONTROL_OIDC_CLIENT_ID=meridian-control-plane
|
||||
# MERIDIAN_CONTROL_OIDC_CLIENT_SECRET=<client secret>
|
||||
#
|
||||
# Point the desktop app at this control plane. There is no default and no
|
||||
# hosted fallback: with either of these missing the app reports community
|
||||
|
|
@ -187,33 +187,33 @@ RELAY_URL=ws://localhost:3000
|
|||
# A packaged app launched from Finder, the Dock, or a deep link inherits no
|
||||
# shell environment, so a build that must create communities has to set these at
|
||||
# BUILD time — they are compiled in as a fallback to the runtime values.
|
||||
# CODEBASE_CHAT_CONTROL_PLANE_URL=http://127.0.0.1:8090/api/codebase
|
||||
# CODEBASE_CHAT_CONTROL_PLANE_ORIGIN=http://127.0.0.1:8090
|
||||
# MERIDIAN_CONTROL_PLANE_URL=http://127.0.0.1:8090/api/codebase
|
||||
# MERIDIAN_CONTROL_PLANE_ORIGIN=http://127.0.0.1:8090
|
||||
|
||||
# Shared Redis-backed admission limits. Defaults shown below; each value must
|
||||
# be a positive integer.
|
||||
# CODEBASE_CHAT_RATE_LIMIT_HUMAN_MESSAGES_PER_MIN=60
|
||||
# CODEBASE_CHAT_RATE_LIMIT_HUMAN_API_CALLS_PER_MIN=300
|
||||
# CODEBASE_CHAT_RATE_LIMIT_HUMAN_WS_EVENTS_PER_SEC=10
|
||||
# CODEBASE_CHAT_RATE_LIMIT_AGENT_STANDARD_MESSAGES_PER_MIN=120
|
||||
# CODEBASE_CHAT_RATE_LIMIT_AGENT_STANDARD_API_CALLS_PER_MIN=600
|
||||
# CODEBASE_CHAT_RATE_LIMIT_AGENT_ELEVATED_MESSAGES_PER_MIN=300
|
||||
# CODEBASE_CHAT_RATE_LIMIT_AGENT_PLATFORM_MESSAGES_PER_MIN=600
|
||||
# MERIDIAN_RATE_LIMIT_HUMAN_MESSAGES_PER_MIN=60
|
||||
# MERIDIAN_RATE_LIMIT_HUMAN_API_CALLS_PER_MIN=300
|
||||
# MERIDIAN_RATE_LIMIT_HUMAN_WS_EVENTS_PER_SEC=10
|
||||
# MERIDIAN_RATE_LIMIT_AGENT_STANDARD_MESSAGES_PER_MIN=120
|
||||
# MERIDIAN_RATE_LIMIT_AGENT_STANDARD_API_CALLS_PER_MIN=600
|
||||
# MERIDIAN_RATE_LIMIT_AGENT_ELEVATED_MESSAGES_PER_MIN=300
|
||||
# MERIDIAN_RATE_LIMIT_AGENT_PLATFORM_MESSAGES_PER_MIN=600
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Git (NIP-34 bare repositories)
|
||||
# -----------------------------------------------------------------------------
|
||||
# Root directory for ephemeral Git workspaces and the disposable pack cache.
|
||||
# Default: ./repos (relative to CWD).
|
||||
# CODEBASE_CHAT_GIT_REPO_PATH=./repos
|
||||
# CODEBASE_CHAT_GIT_MAX_PACK_BYTES=524288000
|
||||
# CODEBASE_CHAT_GIT_MAX_REPO_BYTES=1048576000
|
||||
# MERIDIAN_GIT_REPO_PATH=./repos
|
||||
# MERIDIAN_GIT_MAX_PACK_BYTES=524288000
|
||||
# MERIDIAN_GIT_MAX_REPO_BYTES=1048576000
|
||||
# Process-local immutable pack/index cache. Zero disables retention.
|
||||
# CODEBASE_CHAT_GIT_PACK_CACHE_PATH=./repos/.pack-cache
|
||||
# CODEBASE_CHAT_GIT_PACK_CACHE_MAX_BYTES=5368709120
|
||||
# CODEBASE_CHAT_GIT_PACK_CACHE_MAX_CONCURRENT_POPULATIONS=2
|
||||
# MERIDIAN_GIT_PACK_CACHE_PATH=./repos/.pack-cache
|
||||
# MERIDIAN_GIT_PACK_CACHE_MAX_BYTES=5368709120
|
||||
# MERIDIAN_GIT_PACK_CACHE_MAX_CONCURRENT_POPULATIONS=2
|
||||
# Periodically repair relay-authored 30618 state from authoritative manifests.
|
||||
# CODEBASE_CHAT_GIT_STATE_RECONCILE_INTERVAL_SECS=60
|
||||
# MERIDIAN_GIT_STATE_RECONCILE_INTERVAL_SECS=60
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# S3-Compatible Object Storage (media + Git/CAS)
|
||||
|
|
@ -221,25 +221,25 @@ RELAY_URL=ws://localhost:3000
|
|||
# The local MinIO container is reachable from host processes at localhost:9000.
|
||||
# Path style keeps the bucket in the URL path and is required by this local DNS
|
||||
# setup. Use `virtual` only when the provider requires bucket-as-subdomain URLs.
|
||||
CODEBASE_CHAT_S3_ENDPOINT=http://localhost:9000
|
||||
CODEBASE_CHAT_S3_ACCESS_KEY=codebase_chat_dev
|
||||
CODEBASE_CHAT_S3_SECRET_KEY=codebase_chat_dev_secret
|
||||
CODEBASE_CHAT_S3_BUCKET=codebase-chat-media
|
||||
CODEBASE_CHAT_S3_REGION=us-east-1
|
||||
CODEBASE_CHAT_S3_ADDRESSING_STYLE=path
|
||||
MERIDIAN_S3_ENDPOINT=http://localhost:9000
|
||||
MERIDIAN_S3_ACCESS_KEY=meridian_dev
|
||||
MERIDIAN_S3_SECRET_KEY=meridian_dev_secret
|
||||
MERIDIAN_S3_BUCKET=meridian-media
|
||||
MERIDIAN_S3_REGION=us-east-1
|
||||
MERIDIAN_S3_ADDRESSING_STYLE=path
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Media Upload Admission
|
||||
# -----------------------------------------------------------------------------
|
||||
# Bound image/video parser and storage work admitted by one relay process.
|
||||
# CODEBASE_CHAT_MEDIA_MAX_CONCURRENT_UPLOADS=8
|
||||
# CODEBASE_CHAT_MEDIA_MAX_CONCURRENT_UPLOADS_PER_PUBKEY=2
|
||||
# CODEBASE_CHAT_MEDIA_UPLOADS_PER_MINUTE=30
|
||||
# MERIDIAN_MEDIA_MAX_CONCURRENT_UPLOADS=8
|
||||
# MERIDIAN_MEDIA_MAX_CONCURRENT_UPLOADS_PER_PUBKEY=2
|
||||
# MERIDIAN_MEDIA_UPLOADS_PER_MINUTE=30
|
||||
# Require Blossom t=get auth and relay membership for GET/HEAD /media/*.
|
||||
# Keep off until desktop/mobile/CLI clients that attach media read auth are deployed.
|
||||
# CODEBASE_CHAT_REQUIRE_MEDIA_GET_AUTH=false
|
||||
# MERIDIAN_REQUIRE_MEDIA_GET_AUTH=false
|
||||
# Legacy alias accepted by the relay while rollout docs catch up:
|
||||
# CODEBASE_CHAT_REQUIRE_MEDIA_READ_AUTH=false
|
||||
# MERIDIAN_REQUIRE_MEDIA_READ_AUTH=false
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Ephemeral Channels (TTL testing)
|
||||
|
|
@ -247,95 +247,95 @@ CODEBASE_CHAT_S3_ADDRESSING_STYLE=path
|
|||
# Override the TTL for all ephemeral channels (in seconds). When set, any
|
||||
# channel created with a TTL tag will use this value instead of the
|
||||
# client-provided one. Unset to use the client-provided TTL.
|
||||
# CODEBASE_CHAT_EPHEMERAL_TTL_OVERRIDE=60
|
||||
# MERIDIAN_EPHEMERAL_TTL_OVERRIDE=60
|
||||
|
||||
# How often the reaper checks for expired ephemeral channels (default: 60s).
|
||||
# CODEBASE_CHAT_REAPER_INTERVAL_SECS=5
|
||||
# MERIDIAN_REAPER_INTERVAL_SECS=5
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Logging / Tracing
|
||||
# -----------------------------------------------------------------------------
|
||||
RUST_LOG=codebase_chat_relay=debug,codebase_chat_datastore=info,codebase_chat_db=debug,codebase_chat_auth=debug,codebase_chat_pubsub=debug,tower_http=debug
|
||||
RUST_LOG=meridian_relay=debug,meridian_datastore=info,meridian_db=debug,meridian_auth=debug,meridian_pubsub=debug,tower_http=debug
|
||||
# Optional OpenTelemetry-only target filter. This is deliberately independent
|
||||
# from RUST_LOG so log verbosity changes cannot break trace parentage.
|
||||
# CODEBASE_CHAT_OTEL_FILTER=codebase_chat_relay=info,codebase_chat_datastore=info
|
||||
# MERIDIAN_OTEL_FILTER=meridian_relay=info,meridian_datastore=info
|
||||
|
||||
# OTLP tracing endpoint (optional — leave unset to disable)
|
||||
# OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# ACP (Agent Communication Protocol — codebase-chat-acp harness)
|
||||
# ACP (Agent Communication Protocol — meridian-acp harness)
|
||||
# -----------------------------------------------------------------------------
|
||||
# The ACP harness bridges Codebase Chat events to AI agents. Each env var below maps
|
||||
# The ACP harness bridges Meridian events to AI agents. Each env var below maps
|
||||
# to a CLI flag of the same name (lowercase, hyphens → underscores). All values
|
||||
# are optional unless noted; defaults are shown in comments.
|
||||
#
|
||||
# Quick start:
|
||||
# CODEBASE_CHAT_PRIVATE_KEY=<hex> CODEBASE_CHAT_RELAY_URL=ws://localhost:3000 codebase-chat-acp
|
||||
# MERIDIAN_PRIVATE_KEY=<hex> MERIDIAN_RELAY_URL=ws://localhost:3000 meridian-acp
|
||||
|
||||
# ── Identity & auth ──────────────────────────────────────────────────────────
|
||||
# Nostr private key (hex or bech32). REQUIRED — identifies the agent on the relay.
|
||||
# CODEBASE_CHAT_PRIVATE_KEY=<32-byte hex or nsec1… private key>
|
||||
# MERIDIAN_PRIVATE_KEY=<32-byte hex or nsec1… private key>
|
||||
|
||||
# Relay WebSocket URL the harness connects to.
|
||||
# Note: the relay itself uses RELAY_URL (above); this is the ACP harness's
|
||||
# connection target — they happen to point at the same place in local dev.
|
||||
# CODEBASE_CHAT_RELAY_URL=ws://localhost:3000
|
||||
# MERIDIAN_RELAY_URL=ws://localhost:3000
|
||||
|
||||
# ── Agent subprocess ─────────────────────────────────────────────────────────
|
||||
# Binary to spawn as the AI agent (e.g. "goose", "codex-acp", "claude-code").
|
||||
# CODEBASE_CHAT_ACP_AGENT_COMMAND=goose
|
||||
# MERIDIAN_ACP_AGENT_COMMAND=goose
|
||||
|
||||
# Comma-separated arguments passed to the agent binary.
|
||||
# Goose default: "acp". Codex/Claude default: "" (empty).
|
||||
# CODEBASE_CHAT_ACP_AGENT_ARGS=acp
|
||||
# MERIDIAN_ACP_AGENT_ARGS=acp
|
||||
|
||||
# Binary for an optional MCP server sidecar (e.g. codebase-chat-dev-mcp for codebase-chat-agent).
|
||||
# CODEBASE_CHAT_ACP_MCP_COMMAND=
|
||||
# Binary for an optional MCP server sidecar (e.g. meridian-dev-mcp for meridian-agent).
|
||||
# MERIDIAN_ACP_MCP_COMMAND=
|
||||
|
||||
# Number of parallel agent subprocesses (1–32).
|
||||
# CODEBASE_CHAT_ACP_AGENTS=1
|
||||
# MERIDIAN_ACP_AGENTS=1
|
||||
|
||||
# Desired LLM model ID. Applied to every new ACP session.
|
||||
# Use `codebase-chat-acp models` to discover available model IDs.
|
||||
# CODEBASE_CHAT_ACP_MODEL=
|
||||
# Use `meridian-acp models` to discover available model IDs.
|
||||
# MERIDIAN_ACP_MODEL=
|
||||
|
||||
# ── Timeouts & sessions ──────────────────────────────────────────────────────
|
||||
# Max seconds per agent turn before timeout (default 320 = ~5 min).
|
||||
# CODEBASE_CHAT_ACP_TURN_TIMEOUT=320
|
||||
# MERIDIAN_ACP_TURN_TIMEOUT=320
|
||||
|
||||
# Max turns per session before proactive rotation. 0 = disabled (rotate only
|
||||
# on MaxTokens / MaxTurnRequests). Recommended: 50 for long-running agents.
|
||||
# CODEBASE_CHAT_ACP_MAX_TURNS_PER_SESSION=0
|
||||
# MERIDIAN_ACP_MAX_TURNS_PER_SESSION=0
|
||||
|
||||
# ── Prompts ──────────────────────────────────────────────────────────────────
|
||||
# System prompt injected into every agent session (inline text).
|
||||
# CODEBASE_CHAT_ACP_SYSTEM_PROMPT=
|
||||
# MERIDIAN_ACP_SYSTEM_PROMPT=
|
||||
|
||||
# Path to a file containing the system prompt (mutually exclusive with above).
|
||||
# CODEBASE_CHAT_ACP_SYSTEM_PROMPT_FILE=
|
||||
# MERIDIAN_ACP_SYSTEM_PROMPT_FILE=
|
||||
|
||||
# Message sent to the agent immediately after session creation.
|
||||
# CODEBASE_CHAT_ACP_INITIAL_MESSAGE=
|
||||
# MERIDIAN_ACP_INITIAL_MESSAGE=
|
||||
|
||||
# ── Heartbeat ────────────────────────────────────────────────────────────────
|
||||
# Seconds between heartbeat prompts. 0 = disabled. Must be 0 or ≥10.
|
||||
# Recommended: 60 for long-running agents to prevent idle session timeouts.
|
||||
# CODEBASE_CHAT_ACP_HEARTBEAT_INTERVAL=0
|
||||
# MERIDIAN_ACP_HEARTBEAT_INTERVAL=0
|
||||
|
||||
# Heartbeat prompt text (inline). Mutually exclusive with file variant.
|
||||
# CODEBASE_CHAT_ACP_HEARTBEAT_PROMPT=
|
||||
# MERIDIAN_ACP_HEARTBEAT_PROMPT=
|
||||
|
||||
# Path to a file containing the heartbeat prompt.
|
||||
# CODEBASE_CHAT_ACP_HEARTBEAT_PROMPT_FILE=
|
||||
# MERIDIAN_ACP_HEARTBEAT_PROMPT_FILE=
|
||||
|
||||
# ── Desktop development ──────────────────────────────────────────────────────
|
||||
# DEV-only: replay first-run onboarding and the Welcome Team kickoff on each
|
||||
# app launch while keeping the current identity and relay data.
|
||||
# VITE_CODEBASE_CHAT_FORCE_FRESH_ONBOARDING=true
|
||||
# VITE_MERIDIAN_FORCE_FRESH_ONBOARDING=true
|
||||
|
||||
# DEV-only: resolve the dev identity before launch and pass it to the desktop
|
||||
# app as CODEBASE_CHAT_PRIVATE_KEY, so the app never opens the OS keyring.
|
||||
# app as MERIDIAN_PRIVATE_KEY, so the app never opens the OS keyring.
|
||||
# Two effects:
|
||||
# - macOS stops asking for the login-keychain password after every rebuild
|
||||
# (`tauri dev` emits an ad-hoc signature whose hash changes each build, so
|
||||
|
|
@ -344,66 +344,66 @@ RUST_LOG=codebase_chat_relay=debug,codebase_chat_datastore=info,codebase_chat_db
|
|||
# "Always Allow" holds because Apple's signature is stable.
|
||||
# - worktrees share the main checkout's identity and skip onboarding.
|
||||
# `just desktop-standalone` ignores this and stays on its isolated identity.
|
||||
# NOTE: an explicit CODEBASE_CHAT_PRIVATE_KEY above wins. Setting that var for
|
||||
# NOTE: an explicit MERIDIAN_PRIVATE_KEY above wins. Setting that var for
|
||||
# the ACP harness therefore also becomes the desktop app's identity.
|
||||
# CODEBASE_CHAT_SHARE_IDENTITY=1
|
||||
# MERIDIAN_SHARE_IDENTITY=1
|
||||
|
||||
# ── Subscription & filtering ─────────────────────────────────────────────────
|
||||
# Subscribe mode: "mentions" (default), "all", or "config" (rule-based).
|
||||
# CODEBASE_CHAT_ACP_SUBSCRIBE=mentions
|
||||
# MERIDIAN_ACP_SUBSCRIBE=mentions
|
||||
|
||||
# Comma-separated event kind numbers to subscribe to (overrides mode defaults).
|
||||
# CODEBASE_CHAT_ACP_KINDS=
|
||||
# MERIDIAN_ACP_KINDS=
|
||||
|
||||
# Comma-separated channel UUIDs to limit subscription scope.
|
||||
# CODEBASE_CHAT_ACP_CHANNELS=
|
||||
# MERIDIAN_ACP_CHANNELS=
|
||||
|
||||
# Set to true to disable the @-mention filter in mentions mode.
|
||||
# CODEBASE_CHAT_ACP_NO_MENTION_FILTER=false
|
||||
# MERIDIAN_ACP_NO_MENTION_FILTER=false
|
||||
|
||||
# Path to TOML config file for rule-based subscriptions (config mode).
|
||||
# CODEBASE_CHAT_ACP_CONFIG=./codebase-chat-acp.toml
|
||||
# MERIDIAN_ACP_CONFIG=./meridian-acp.toml
|
||||
|
||||
# ── Dedup & self-ignore ──────────────────────────────────────────────────────
|
||||
# How to handle duplicate events: "queue" (default) or "drop".
|
||||
# CODEBASE_CHAT_ACP_DEDUP=queue
|
||||
# MERIDIAN_ACP_DEDUP=queue
|
||||
|
||||
# Set to true to process the agent's own messages (default: ignore self).
|
||||
# CODEBASE_CHAT_ACP_NO_IGNORE_SELF=false
|
||||
# MERIDIAN_ACP_NO_IGNORE_SELF=false
|
||||
|
||||
# ── Context ──────────────────────────────────────────────────────────────────
|
||||
# Max context messages fetched for thread replies and DMs (0–100). 0 = disabled.
|
||||
# CODEBASE_CHAT_ACP_CONTEXT_MESSAGE_LIMIT=12
|
||||
# MERIDIAN_ACP_CONTEXT_MESSAGE_LIMIT=12
|
||||
|
||||
# ── Presence & typing ────────────────────────────────────────────────────────
|
||||
# Set to true to disable automatic online/offline presence status.
|
||||
# CODEBASE_CHAT_ACP_NO_PRESENCE=false
|
||||
# MERIDIAN_ACP_NO_PRESENCE=false
|
||||
|
||||
# Set to true to disable typing indicators while the agent is processing.
|
||||
# CODEBASE_CHAT_ACP_NO_TYPING=false
|
||||
# MERIDIAN_ACP_NO_TYPING=false
|
||||
|
||||
# ── Advanced tuning ──────────────────────────────────────────────────────────
|
||||
# Event channel buffer capacity (WebSocket → harness). Increase for
|
||||
# high-throughput agents. Minimum 1.
|
||||
# CODEBASE_CHAT_ACP_EVENT_BUFFER=256
|
||||
# MERIDIAN_ACP_EVENT_BUFFER=256
|
||||
|
||||
# ── Legacy aliases ───────────────────────────────────────────────────────────
|
||||
# These are accepted for backward compatibility but the canonical names above
|
||||
# are preferred:
|
||||
# CODEBASE_CHAT_ACP_PRIVATE_KEY → CODEBASE_CHAT_PRIVATE_KEY
|
||||
# MERIDIAN_ACP_PRIVATE_KEY → MERIDIAN_PRIVATE_KEY
|
||||
|
||||
# Optional relay join policy. Markdown is served by the relay so every join
|
||||
# surface can present the same documents. Each document and the independent age
|
||||
# attestation are optional; configuring any one enables policy acceptance.
|
||||
# CODEBASE_CHAT_TERMS_OF_SERVICE_MARKDOWN="# Terms of Service\n\nFull terms here."
|
||||
# CODEBASE_CHAT_PRIVACY_POLICY_MARKDOWN="# Privacy Policy\n\nFull policy here."
|
||||
# CODEBASE_CHAT_AGE_ATTESTATION_REQUIRED=true
|
||||
# MERIDIAN_TERMS_OF_SERVICE_MARKDOWN="# Terms of Service\n\nFull terms here."
|
||||
# MERIDIAN_PRIVACY_POLICY_MARKDOWN="# Privacy Policy\n\nFull policy here."
|
||||
# MERIDIAN_AGE_ATTESTATION_REQUIRED=true
|
||||
|
||||
# 32-byte hexadecimal root for encrypted workflow credentials. Required before
|
||||
# any {{secret.NAME}} reference can be written or executed. Supply it through
|
||||
# the deployment secret/KMS path and include the key version in recovery drills.
|
||||
# CODEBASE_CHAT_WORKFLOW_SECRET_KEY=
|
||||
# MERIDIAN_WORKFLOW_SECRET_KEY=
|
||||
# Expand/contract barrier. Keep false while N-1 is a supported rollback target.
|
||||
# Enabling permits {{secret.NAME}} definitions and removes legacy webhook
|
||||
# credentials as definitions are migrated/edited.
|
||||
CODEBASE_CHAT_WORKFLOW_SECRET_REFS_ENABLED=false
|
||||
MERIDIAN_WORKFLOW_SECRET_REFS_ENABLED=false
|
||||
|
|
|
|||
2
.github/AGENTS.md
vendored
2
.github/AGENTS.md
vendored
|
|
@ -18,7 +18,7 @@ other tree.
|
|||
| `mobile-release-candidate.yml` | Mobile RC publishing |
|
||||
| `signed-macos-canary.yml`, `linux-canary.yml`, `windows-canary.yml` | Platform canaries |
|
||||
| `sprig.yml` | Sprig harness bundle |
|
||||
| `benchmark-harbor.yml` | `benchmarks/harbor-codebase-chat-orchestra` run |
|
||||
| `benchmark-harbor.yml` | `benchmarks/harbor-meridian-orchestra` run |
|
||||
|
||||
Also: `CODEOWNERS`, `PULL_REQUEST_TEMPLATE.md`, `ISSUE_TEMPLATE/`
|
||||
(`bug-report.md`, `feature-request.md`, `config.yml`).
|
||||
|
|
|
|||
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
|
|
@ -1 +1 @@
|
|||
* @block/codebase-chat-oss-team
|
||||
* @block/meridian-oss-team
|
||||
|
|
|
|||
4
.github/ISSUE_TEMPLATE/bug-report.md
vendored
4
.github/ISSUE_TEMPLATE/bug-report.md
vendored
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
name: Bug report
|
||||
about: Report a reproducible bug in Codebase Chat
|
||||
about: Report a reproducible bug in Meridian
|
||||
labels: bug
|
||||
---
|
||||
|
||||
|
|
@ -17,7 +17,7 @@ What did you expect to happen?
|
|||
|
||||
**Version and platform**
|
||||
Find your version at the bottom of the Settings sidebar. Write "unknown" if you can't determine it.
|
||||
- Codebase Chat version:
|
||||
- Meridian version:
|
||||
- OS:
|
||||
|
||||
**Logs / additional context**
|
||||
|
|
|
|||
2
.github/ISSUE_TEMPLATE/feature-request.md
vendored
2
.github/ISSUE_TEMPLATE/feature-request.md
vendored
|
|
@ -18,4 +18,4 @@ Anything else that helps — links, screenshots, prior art.
|
|||
|
||||
---
|
||||
|
||||
Before opening: please [search open issues and PRs](https://github.com/codebase/codebase-chat/issues?q=is%3Aopen) for duplicates — link the closest one, or say "none found".
|
||||
Before opening: please [search open issues and PRs](https://github.com/r2d2/meridian/issues?q=is%3Aopen) for duplicates — link the closest one, or say "none found".
|
||||
|
|
|
|||
|
|
@ -8,20 +8,20 @@ name: Auto-tag on Release PR Merge
|
|||
# relay-release/<v> → tag relay-v<v> → docker.yml (relay image)
|
||||
# chart-release/<v> → tag chart-v<v> → helm-chart.yml (main helm chart)
|
||||
# push-chart-release/<v> → tag push-chart-v<v> → push-gateway-helm-chart.yml
|
||||
# any internal PR that bumps deploy/charts/codebase-chat/Chart.yaml `version`
|
||||
# any internal PR that bumps deploy/charts/meridian/Chart.yaml `version`
|
||||
# → tag chart-v<v> → helm-chart.yml (helm chart)
|
||||
#
|
||||
# Mobile candidate tags do not come from merged PRs. Operators create immutable
|
||||
# mobile-v<v>-rc.N tags directly from remote main with scripts/mobile-release.sh,
|
||||
# then hand the exact tag to codebase-chat-releases.
|
||||
# then hand the exact tag to meridian-releases.
|
||||
#
|
||||
# Release tags are created with a short-lived token from the dedicated
|
||||
# codebase-chat-release-bot GitHub App. GitHub attributes the ref creation to that
|
||||
# meridian-release-bot GitHub App. GitHub attributes the ref creation to that
|
||||
# App, so the consumer's `on.push.tags` trigger runs normally. The workflow's
|
||||
# default GITHUB_TOKEN remains read-only and is never used to create a tag.
|
||||
#
|
||||
# Mobile is manual-only by infosec necessity: OSS `codebase/codebase-chat` CI must
|
||||
# not trigger CI in the private `codebase-chat-releases` repo. A human feeds the exact
|
||||
# Mobile is manual-only by infosec necessity: OSS `r2d2/meridian` CI must
|
||||
# not trigger CI in the private `meridian-releases` repo. A human feeds the exact
|
||||
# mobile candidate tag to the private Buildkite pipeline, which builds and
|
||||
# ships mobile.
|
||||
|
||||
|
|
@ -69,8 +69,8 @@ jobs:
|
|||
TAG_PREFIX="push-chart-v" ;;
|
||||
*)
|
||||
parent_sha="$(git rev-parse HEAD^)"
|
||||
old_version="$(git show "${parent_sha}:deploy/charts/codebase-chat/Chart.yaml" 2>/dev/null | awk '/^version:/ {print $2}')"
|
||||
VERSION="$(awk '/^version:/ {print $2}' deploy/charts/codebase-chat/Chart.yaml)"
|
||||
old_version="$(git show "${parent_sha}:deploy/charts/meridian/Chart.yaml" 2>/dev/null | awk '/^version:/ {print $2}')"
|
||||
VERSION="$(awk '/^version:/ {print $2}' deploy/charts/meridian/Chart.yaml)"
|
||||
if [ -z "$old_version" ] || [ -z "$VERSION" ] || [ "$old_version" = "$VERSION" ]; then
|
||||
echo "No release branch or chart version bump — nothing to tag"
|
||||
echo "enabled=false" >> "$GITHUB_OUTPUT"
|
||||
|
|
@ -93,8 +93,8 @@ jobs:
|
|||
id: release-tagger
|
||||
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
|
||||
with:
|
||||
client-id: ${{ vars.CODEBASE_CHAT_RELEASE_TAGGER_CLIENT_ID }}
|
||||
private-key: ${{ secrets.CODEBASE_CHAT_RELEASE_TAGGER_PRIVATE_KEY }}
|
||||
client-id: ${{ vars.MERIDIAN_RELEASE_TAGGER_CLIENT_ID }}
|
||||
private-key: ${{ secrets.MERIDIAN_RELEASE_TAGGER_PRIVATE_KEY }}
|
||||
permission-contents: write
|
||||
|
||||
- name: Create and push tag
|
||||
|
|
|
|||
10
.github/workflows/benchmark-harbor.yml
vendored
10
.github/workflows/benchmark-harbor.yml
vendored
|
|
@ -1,14 +1,14 @@
|
|||
name: Harbor Codebase Chat Orchestra
|
||||
name: Harbor Meridian Orchestra
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- "benchmarks/harbor-codebase-chat-orchestra/**"
|
||||
- "benchmarks/harbor-meridian-orchestra/**"
|
||||
- ".github/workflows/benchmark-harbor.yml"
|
||||
pull_request:
|
||||
paths:
|
||||
- "benchmarks/harbor-codebase-chat-orchestra/**"
|
||||
- "benchmarks/harbor-meridian-orchestra/**"
|
||||
- ".github/workflows/benchmark-harbor.yml"
|
||||
|
||||
permissions:
|
||||
|
|
@ -32,13 +32,13 @@ jobs:
|
|||
- name: Install uv
|
||||
run: python -m pip install --disable-pip-version-check "uv>=0.8,<0.9"
|
||||
- name: Test adapter
|
||||
working-directory: benchmarks/harbor-codebase-chat-orchestra
|
||||
working-directory: benchmarks/harbor-meridian-orchestra
|
||||
run: |
|
||||
uv sync --locked --extra dev
|
||||
uv run --no-sync pytest -q
|
||||
uv run --no-sync ruff check .
|
||||
- name: Test provisioner
|
||||
working-directory: benchmarks/harbor-codebase-chat-orchestra/testbed
|
||||
working-directory: benchmarks/harbor-meridian-orchestra/testbed
|
||||
run: |
|
||||
uv sync --locked --extra dev
|
||||
uv run --no-sync pytest -q
|
||||
|
|
|
|||
260
.github/workflows/ci.yml
vendored
260
.github/workflows/ci.yml
vendored
|
|
@ -13,7 +13,7 @@ concurrency:
|
|||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
CODEBASE_CHAT_TEST_POSTGRES_PASSWORD: codebase_chat_dev
|
||||
MERIDIAN_TEST_POSTGRES_PASSWORD: meridian_dev
|
||||
PLAYWRIGHT_BROWSERS_PATH: ${{ github.workspace }}/.cache/ms-playwright
|
||||
|
||||
jobs:
|
||||
|
|
@ -347,7 +347,7 @@ jobs:
|
|||
uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5
|
||||
with:
|
||||
path: |
|
||||
target/ci/codebase-chat-relay
|
||||
target/ci/meridian-relay
|
||||
target/ci/git-credential-nostr
|
||||
target/ci/backend-integration-tests.tar.zst
|
||||
key: relay-artifacts-${{ runner.os }}-${{ hashFiles('crates/**', 'migrations/**', 'Dockerfile', 'Cargo.toml', 'Cargo.lock', 'rust-toolchain.toml', '.cargo/config.toml', '.github/workflows/ci.yml') }}
|
||||
|
|
@ -368,12 +368,12 @@ jobs:
|
|||
- name: Build relay artifacts
|
||||
if: steps.relay-artifacts-cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
cargo build --profile ci -p codebase-chat-relay -p git-credential-nostr
|
||||
cargo build --profile ci -p meridian-relay -p git-credential-nostr
|
||||
cargo nextest archive \
|
||||
--cargo-profile ci \
|
||||
-p codebase-chat-db \
|
||||
-p codebase-chat-relay \
|
||||
-p codebase-chat-test-client \
|
||||
-p meridian-db \
|
||||
-p meridian-relay \
|
||||
-p meridian-test-client \
|
||||
--lib \
|
||||
--test e2e_event_reminder \
|
||||
--archive-file target/ci/backend-integration-tests.tar.zst
|
||||
|
|
@ -382,7 +382,7 @@ jobs:
|
|||
uses: actions/cache/save@caa296126883cff596d87d8935842f9db880ef25 # v5
|
||||
with:
|
||||
path: |
|
||||
target/ci/codebase-chat-relay
|
||||
target/ci/meridian-relay
|
||||
target/ci/git-credential-nostr
|
||||
target/ci/backend-integration-tests.tar.zst
|
||||
key: relay-artifacts-${{ runner.os }}-${{ hashFiles('crates/**', 'migrations/**', 'Dockerfile', 'Cargo.toml', 'Cargo.lock', 'rust-toolchain.toml', '.cargo/config.toml', '.github/workflows/ci.yml') }}
|
||||
|
|
@ -391,7 +391,7 @@ jobs:
|
|||
with:
|
||||
name: desktop-e2e-relay
|
||||
path: |
|
||||
target/ci/codebase-chat-relay
|
||||
target/ci/meridian-relay
|
||||
target/ci/git-credential-nostr
|
||||
target/ci/backend-integration-tests.tar.zst
|
||||
if-no-files-found: error
|
||||
|
|
@ -474,9 +474,9 @@ jobs:
|
|||
docker logs "${container}" || true
|
||||
return 1
|
||||
}
|
||||
wait_healthy "Postgres" "codebase-chat-postgres"
|
||||
wait_healthy "Dragonfly" "codebase-chat-dragonfly"
|
||||
wait_healthy "MinIO" "codebase-chat-minio"
|
||||
wait_healthy "Postgres" "meridian-postgres"
|
||||
wait_healthy "Dragonfly" "meridian-dragonfly"
|
||||
wait_healthy "MinIO" "meridian-minio"
|
||||
- name: Download relay binary
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
|
|
@ -489,54 +489,54 @@ jobs:
|
|||
# exits permanently on an unmapped host, so the 'localhost:3000'
|
||||
# community MUST exist before the relay starts — the retry loop only
|
||||
# handles late-seeded channels, not a late-seeded community. The relay
|
||||
# migrates at boot via CODEBASE_CHAT_AUTO_MIGRATE, but that's too late for the
|
||||
# migrates at boot via MERIDIAN_AUTO_MIGRATE, but that's too late for the
|
||||
# pre-boot seed, so apply the schema here first (then drop AUTO_MIGRATE
|
||||
# below). lower(host) is the unique index → ON CONFLICT target. psql
|
||||
# isn't on PATH in hermit → exec into the codebase-chat-postgres container.
|
||||
# isn't on PATH in hermit → exec into the meridian-postgres container.
|
||||
env:
|
||||
PGHOST: localhost
|
||||
PGPORT: "5432"
|
||||
PGUSER: codebase-chat
|
||||
PGPASSWORD: codebase_chat_dev
|
||||
PGDATABASE: codebase-chat
|
||||
PGUSER: meridian
|
||||
PGPASSWORD: meridian_dev
|
||||
PGDATABASE: meridian
|
||||
# Use the already-running docker postgres for desired-state planning instead of
|
||||
# downloading an embedded Postgres from Maven Central (transient-fetch flake source).
|
||||
PGSCHEMA_PLAN_HOST: localhost
|
||||
PGSCHEMA_PLAN_PORT: "5432"
|
||||
PGSCHEMA_PLAN_DB: codebase-chat
|
||||
PGSCHEMA_PLAN_USER: codebase-chat
|
||||
PGSCHEMA_PLAN_PASSWORD: codebase_chat_dev
|
||||
PGSCHEMA_PLAN_DB: meridian
|
||||
PGSCHEMA_PLAN_USER: meridian
|
||||
PGSCHEMA_PLAN_PASSWORD: meridian_dev
|
||||
run: |
|
||||
./bin/pgschema apply --file schema/schema.sql --auto-approve
|
||||
docker exec -i -e PGPASSWORD=codebase_chat_dev codebase-chat-postgres \
|
||||
psql -U codebase_chat -d codebase_chat -v ON_ERROR_STOP=1 < scripts/attach-schema-partitions.sql
|
||||
docker exec -e PGPASSWORD=codebase_chat_dev codebase-chat-postgres \
|
||||
psql -U codebase_chat -d codebase_chat -qtA -c "
|
||||
docker exec -i -e PGPASSWORD=meridian_dev meridian-postgres \
|
||||
psql -U meridian -d meridian -v ON_ERROR_STOP=1 < scripts/attach-schema-partitions.sql
|
||||
docker exec -e PGPASSWORD=meridian_dev meridian-postgres \
|
||||
psql -U meridian -d meridian -qtA -c "
|
||||
INSERT INTO communities (id, host)
|
||||
VALUES ('00000000-0000-4000-8000-00000000c0de', 'localhost:3000')
|
||||
ON CONFLICT (lower(host)) DO NOTHING
|
||||
;"
|
||||
- name: Start relay
|
||||
run: |
|
||||
chmod +x ./target/ci/codebase-chat-relay
|
||||
chmod +x ./target/ci/meridian-relay
|
||||
nohup env \
|
||||
DATABASE_URL="postgres://codebase_chat:${CODEBASE_CHAT_TEST_POSTGRES_PASSWORD}@localhost:5432/codebase_chat" \
|
||||
DATABASE_URL="postgres://meridian:${MERIDIAN_TEST_POSTGRES_PASSWORD}@localhost:5432/meridian" \
|
||||
REDIS_URL=redis://localhost:6379 \
|
||||
RELAY_URL=ws://localhost:3000 \
|
||||
CODEBASE_CHAT_BIND_ADDR=0.0.0.0:3000 \
|
||||
CODEBASE_CHAT_REQUIRE_AUTH_TOKEN=false \
|
||||
CODEBASE_CHAT_WORKFLOW_SECRET_KEY=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef \
|
||||
CODEBASE_CHAT_RECONCILE_CHANNELS=true \
|
||||
CODEBASE_CHAT_RATE_LIMIT_HUMAN_MESSAGES_PER_MIN=100000 \
|
||||
CODEBASE_CHAT_RATE_LIMIT_HUMAN_API_CALLS_PER_MIN=100000 \
|
||||
CODEBASE_CHAT_RATE_LIMIT_HUMAN_WS_EVENTS_PER_SEC=10000 \
|
||||
CODEBASE_CHAT_GIT_PROBE_WRITERS=8 \
|
||||
MERIDIAN_BIND_ADDR=0.0.0.0:3000 \
|
||||
MERIDIAN_REQUIRE_AUTH_TOKEN=false \
|
||||
MERIDIAN_WORKFLOW_SECRET_KEY=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef \
|
||||
MERIDIAN_RECONCILE_CHANNELS=true \
|
||||
MERIDIAN_RATE_LIMIT_HUMAN_MESSAGES_PER_MIN=100000 \
|
||||
MERIDIAN_RATE_LIMIT_HUMAN_API_CALLS_PER_MIN=100000 \
|
||||
MERIDIAN_RATE_LIMIT_HUMAN_WS_EVENTS_PER_SEC=10000 \
|
||||
MERIDIAN_GIT_PROBE_WRITERS=8 \
|
||||
SPROUT_REMINDER_SCHEDULER_INTERVAL_SECS=1 \
|
||||
./target/ci/codebase-chat-relay > /tmp/codebase-chat-relay.log 2>&1 &
|
||||
echo $! > /tmp/codebase-chat-relay.pid
|
||||
./target/ci/meridian-relay > /tmp/meridian-relay.log 2>&1 &
|
||||
echo $! > /tmp/meridian-relay.pid
|
||||
for attempt in $(seq 1 60); do
|
||||
if ! kill -0 "$(cat /tmp/codebase-chat-relay.pid)" 2>/dev/null; then
|
||||
cat /tmp/codebase-chat-relay.log
|
||||
if ! kill -0 "$(cat /tmp/meridian-relay.pid)" 2>/dev/null; then
|
||||
cat /tmp/meridian-relay.log
|
||||
exit 1
|
||||
fi
|
||||
status_code=$(curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:3000/_readiness || true)
|
||||
|
|
@ -545,7 +545,7 @@ jobs:
|
|||
fi
|
||||
sleep 1
|
||||
done
|
||||
cat /tmp/codebase-chat-relay.log
|
||||
cat /tmp/meridian-relay.log
|
||||
exit 1
|
||||
- name: Seed desktop e2e data
|
||||
run: bash scripts/setup-desktop-test-data.sh
|
||||
|
|
@ -564,7 +564,7 @@ jobs:
|
|||
desktop/playwright-report
|
||||
desktop/playwright-report.json
|
||||
desktop/test-results
|
||||
/tmp/codebase-chat-relay.log
|
||||
/tmp/meridian-relay.log
|
||||
if-no-files-found: ignore
|
||||
retention-days: 7
|
||||
- name: Save pnpm store cache
|
||||
|
|
@ -635,9 +635,9 @@ jobs:
|
|||
docker logs "${container}" || true
|
||||
return 1
|
||||
}
|
||||
wait_healthy "Postgres" "codebase-chat-postgres"
|
||||
wait_healthy "Dragonfly" "codebase-chat-dragonfly"
|
||||
wait_healthy "MinIO" "codebase-chat-minio"
|
||||
wait_healthy "Postgres" "meridian-postgres"
|
||||
wait_healthy "Dragonfly" "meridian-dragonfly"
|
||||
wait_healthy "MinIO" "meridian-minio"
|
||||
- name: Download relay artifacts
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
|
|
@ -650,51 +650,51 @@ jobs:
|
|||
# unmapped host (no retry, unlike the channel reconciler), so the
|
||||
# 'localhost:3000' community MUST exist before the relay starts — seeding
|
||||
# after boot leaves the scheduler dead. The relay migrates at boot via
|
||||
# CODEBASE_CHAT_AUTO_MIGRATE, but that's too late for the pre-boot seed, so apply
|
||||
# MERIDIAN_AUTO_MIGRATE, but that's too late for the pre-boot seed, so apply
|
||||
# the schema here first (then drop AUTO_MIGRATE below). lower(host) is the
|
||||
# unique index → ON CONFLICT target. psql isn't on PATH in hermit → exec
|
||||
# into the codebase-chat-postgres container.
|
||||
# into the meridian-postgres container.
|
||||
env:
|
||||
PGHOST: localhost
|
||||
PGPORT: "5432"
|
||||
PGUSER: codebase-chat
|
||||
PGPASSWORD: codebase_chat_dev
|
||||
PGDATABASE: codebase-chat
|
||||
PGUSER: meridian
|
||||
PGPASSWORD: meridian_dev
|
||||
PGDATABASE: meridian
|
||||
# Use the already-running docker postgres for desired-state planning instead of
|
||||
# downloading an embedded Postgres from Maven Central (transient-fetch flake source).
|
||||
PGSCHEMA_PLAN_HOST: localhost
|
||||
PGSCHEMA_PLAN_PORT: "5432"
|
||||
PGSCHEMA_PLAN_DB: codebase-chat
|
||||
PGSCHEMA_PLAN_USER: codebase-chat
|
||||
PGSCHEMA_PLAN_PASSWORD: codebase_chat_dev
|
||||
PGSCHEMA_PLAN_DB: meridian
|
||||
PGSCHEMA_PLAN_USER: meridian
|
||||
PGSCHEMA_PLAN_PASSWORD: meridian_dev
|
||||
run: |
|
||||
./bin/pgschema apply --file schema/schema.sql --auto-approve
|
||||
docker exec -i -e PGPASSWORD=codebase_chat_dev codebase-chat-postgres \
|
||||
psql -U codebase_chat -d codebase_chat -v ON_ERROR_STOP=1 < scripts/attach-schema-partitions.sql
|
||||
docker exec -e PGPASSWORD=codebase_chat_dev codebase-chat-postgres \
|
||||
psql -U codebase_chat -d codebase_chat -qtA -c "
|
||||
docker exec -i -e PGPASSWORD=meridian_dev meridian-postgres \
|
||||
psql -U meridian -d meridian -v ON_ERROR_STOP=1 < scripts/attach-schema-partitions.sql
|
||||
docker exec -e PGPASSWORD=meridian_dev meridian-postgres \
|
||||
psql -U meridian -d meridian -qtA -c "
|
||||
INSERT INTO communities (id, host)
|
||||
VALUES ('00000000-0000-4000-8000-00000000c0de', 'localhost:3000')
|
||||
ON CONFLICT (lower(host)) DO NOTHING
|
||||
;"
|
||||
- name: Start relay
|
||||
run: |
|
||||
chmod +x ./target/ci/codebase-chat-relay
|
||||
chmod +x ./target/ci/meridian-relay
|
||||
nohup env \
|
||||
DATABASE_URL="postgres://codebase_chat:${CODEBASE_CHAT_TEST_POSTGRES_PASSWORD}@localhost:5432/codebase_chat" \
|
||||
DATABASE_URL="postgres://meridian:${MERIDIAN_TEST_POSTGRES_PASSWORD}@localhost:5432/meridian" \
|
||||
REDIS_URL=redis://localhost:6379 \
|
||||
RELAY_URL=ws://localhost:3000 \
|
||||
CODEBASE_CHAT_BIND_ADDR=0.0.0.0:3000 \
|
||||
CODEBASE_CHAT_REQUIRE_AUTH_TOKEN=false \
|
||||
CODEBASE_CHAT_WORKFLOW_SECRET_KEY=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef \
|
||||
CODEBASE_CHAT_RECONCILE_CHANNELS=true \
|
||||
CODEBASE_CHAT_GIT_PROBE_WRITERS=8 \
|
||||
MERIDIAN_BIND_ADDR=0.0.0.0:3000 \
|
||||
MERIDIAN_REQUIRE_AUTH_TOKEN=false \
|
||||
MERIDIAN_WORKFLOW_SECRET_KEY=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef \
|
||||
MERIDIAN_RECONCILE_CHANNELS=true \
|
||||
MERIDIAN_GIT_PROBE_WRITERS=8 \
|
||||
SPROUT_REMINDER_SCHEDULER_INTERVAL_SECS=1 \
|
||||
./target/ci/codebase-chat-relay > /tmp/codebase-chat-relay.log 2>&1 &
|
||||
echo $! > /tmp/codebase-chat-relay.pid
|
||||
./target/ci/meridian-relay > /tmp/meridian-relay.log 2>&1 &
|
||||
echo $! > /tmp/meridian-relay.pid
|
||||
for attempt in $(seq 1 60); do
|
||||
if ! kill -0 "$(cat /tmp/codebase-chat-relay.pid)" 2>/dev/null; then
|
||||
cat /tmp/codebase-chat-relay.log
|
||||
if ! kill -0 "$(cat /tmp/meridian-relay.pid)" 2>/dev/null; then
|
||||
cat /tmp/meridian-relay.log
|
||||
exit 1
|
||||
fi
|
||||
status_code=$(curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:3000/_readiness || true)
|
||||
|
|
@ -703,21 +703,21 @@ jobs:
|
|||
fi
|
||||
sleep 1
|
||||
done
|
||||
cat /tmp/codebase-chat-relay.log
|
||||
cat /tmp/meridian-relay.log
|
||||
exit 1
|
||||
- name: Invite security tests
|
||||
run: |
|
||||
cargo nextest run \
|
||||
--archive-file target/ci/backend-integration-tests.tar.zst \
|
||||
-E '(package(codebase-chat-db) and test(/relay_invite::tests/)) or (package(codebase-chat-relay) and test(/api::invites::tests/))' \
|
||||
-E '(package(meridian-db) and test(/relay_invite::tests/)) or (package(meridian-relay) and test(/api::invites::tests/))' \
|
||||
--run-ignored ignored-only
|
||||
env:
|
||||
DATABASE_URL: postgres://codebase_chat:${{ env.CODEBASE_CHAT_TEST_POSTGRES_PASSWORD }}@localhost:5432/codebase_chat
|
||||
DATABASE_URL: postgres://meridian:${{ env.MERIDIAN_TEST_POSTGRES_PASSWORD }}@localhost:5432/meridian
|
||||
- name: NIP-ER reminder e2e
|
||||
# Feature e2e for NIP-ER (Event Reminders, kind:30300): write-path
|
||||
# validation, author-only read filtering, and scheduler delivery against
|
||||
# a live relay. The schema-drift / migration-version guarantee is owned
|
||||
# by the codebase-chat-db migration.rs unit tests, not this suite.
|
||||
# by the meridian-db migration.rs unit tests, not this suite.
|
||||
run: |
|
||||
cargo nextest run \
|
||||
--archive-file target/ci/backend-integration-tests.tar.zst \
|
||||
|
|
@ -730,7 +730,7 @@ jobs:
|
|||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
with:
|
||||
name: backend-integration-relay-log
|
||||
path: /tmp/codebase-chat-relay.log
|
||||
path: /tmp/meridian-relay.log
|
||||
if-no-files-found: ignore
|
||||
|
||||
relay-e2e:
|
||||
|
|
@ -756,32 +756,32 @@ jobs:
|
|||
path: target/ci
|
||||
- name: Start relay
|
||||
run: |
|
||||
chmod +x ./target/ci/codebase-chat-relay ./target/ci/git-credential-nostr
|
||||
CODEBASE_CHAT_MAX_CONCURRENT_HANDLERS=2048 \
|
||||
CODEBASE_CHAT_RATE_LIMIT_HUMAN_WS_EVENTS_PER_SEC=5000 \
|
||||
CODEBASE_CHAT_SEND_BUFFER=4096 \
|
||||
chmod +x ./target/ci/meridian-relay ./target/ci/git-credential-nostr
|
||||
MERIDIAN_MAX_CONCURRENT_HANDLERS=2048 \
|
||||
MERIDIAN_RATE_LIMIT_HUMAN_WS_EVENTS_PER_SEC=5000 \
|
||||
MERIDIAN_SEND_BUFFER=4096 \
|
||||
./scripts/start-relay-for-tests.sh --no-build
|
||||
- name: Start second relay replica
|
||||
run: |
|
||||
nohup env \
|
||||
DATABASE_URL=postgres://codebase_chat:codebase_chat_dev@localhost:5432/codebase_chat \
|
||||
DATABASE_URL=postgres://meridian:meridian_dev@localhost:5432/meridian \
|
||||
REDIS_URL=redis://localhost:6379 \
|
||||
RELAY_URL=ws://localhost:3000 \
|
||||
CODEBASE_CHAT_BIND_ADDR=0.0.0.0:3001 \
|
||||
CODEBASE_CHAT_HEALTH_PORT=8081 \
|
||||
CODEBASE_CHAT_METRICS_PORT=9103 \
|
||||
CODEBASE_CHAT_REQUIRE_AUTH_TOKEN=false \
|
||||
CODEBASE_CHAT_WORKFLOW_SECRET_KEY=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef \
|
||||
CODEBASE_CHAT_MAX_CONCURRENT_HANDLERS=2048 \
|
||||
CODEBASE_CHAT_RATE_LIMIT_HUMAN_WS_EVENTS_PER_SEC=5000 \
|
||||
CODEBASE_CHAT_SEND_BUFFER=4096 \
|
||||
CODEBASE_CHAT_RECONCILE_CHANNELS=true \
|
||||
CODEBASE_CHAT_GIT_PROBE_WRITERS=8 \
|
||||
./target/ci/codebase-chat-relay > /tmp/codebase-chat-relay-b.log 2>&1 &
|
||||
echo $! > /tmp/codebase-chat-relay-b.pid
|
||||
MERIDIAN_BIND_ADDR=0.0.0.0:3001 \
|
||||
MERIDIAN_HEALTH_PORT=8081 \
|
||||
MERIDIAN_METRICS_PORT=9103 \
|
||||
MERIDIAN_REQUIRE_AUTH_TOKEN=false \
|
||||
MERIDIAN_WORKFLOW_SECRET_KEY=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef \
|
||||
MERIDIAN_MAX_CONCURRENT_HANDLERS=2048 \
|
||||
MERIDIAN_RATE_LIMIT_HUMAN_WS_EVENTS_PER_SEC=5000 \
|
||||
MERIDIAN_SEND_BUFFER=4096 \
|
||||
MERIDIAN_RECONCILE_CHANNELS=true \
|
||||
MERIDIAN_GIT_PROBE_WRITERS=8 \
|
||||
./target/ci/meridian-relay > /tmp/meridian-relay-b.log 2>&1 &
|
||||
echo $! > /tmp/meridian-relay-b.pid
|
||||
for attempt in $(seq 1 60); do
|
||||
if ! kill -0 "$(cat /tmp/codebase-chat-relay-b.pid)" 2>/dev/null; then
|
||||
cat /tmp/codebase-chat-relay-b.log
|
||||
if ! kill -0 "$(cat /tmp/meridian-relay-b.pid)" 2>/dev/null; then
|
||||
cat /tmp/meridian-relay-b.log
|
||||
exit 1
|
||||
fi
|
||||
if [[ "$(curl -s -o /dev/null -w '%{http_code}' -H 'Host: localhost:3000' http://127.0.0.1:3001/_readiness || true)" == 200 ]]; then
|
||||
|
|
@ -789,26 +789,26 @@ jobs:
|
|||
fi
|
||||
sleep 1
|
||||
done
|
||||
cat /tmp/codebase-chat-relay-b.log
|
||||
cat /tmp/meridian-relay-b.log
|
||||
exit 1
|
||||
- name: Start default-admission relay replica
|
||||
run: |
|
||||
nohup env \
|
||||
DATABASE_URL=postgres://codebase_chat:codebase_chat_dev@localhost:5432/codebase_chat \
|
||||
DATABASE_URL=postgres://meridian:meridian_dev@localhost:5432/meridian \
|
||||
REDIS_URL=redis://localhost:6379 \
|
||||
RELAY_URL=ws://localhost:3000 \
|
||||
CODEBASE_CHAT_BIND_ADDR=0.0.0.0:3002 \
|
||||
CODEBASE_CHAT_HEALTH_PORT=8082 \
|
||||
CODEBASE_CHAT_METRICS_PORT=9104 \
|
||||
CODEBASE_CHAT_REQUIRE_AUTH_TOKEN=false \
|
||||
CODEBASE_CHAT_WORKFLOW_SECRET_KEY=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef \
|
||||
CODEBASE_CHAT_RECONCILE_CHANNELS=true \
|
||||
CODEBASE_CHAT_GIT_PROBE_WRITERS=8 \
|
||||
./target/ci/codebase-chat-relay > /tmp/codebase-chat-relay-default-admission.log 2>&1 &
|
||||
echo $! > /tmp/codebase-chat-relay-default-admission.pid
|
||||
MERIDIAN_BIND_ADDR=0.0.0.0:3002 \
|
||||
MERIDIAN_HEALTH_PORT=8082 \
|
||||
MERIDIAN_METRICS_PORT=9104 \
|
||||
MERIDIAN_REQUIRE_AUTH_TOKEN=false \
|
||||
MERIDIAN_WORKFLOW_SECRET_KEY=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef \
|
||||
MERIDIAN_RECONCILE_CHANNELS=true \
|
||||
MERIDIAN_GIT_PROBE_WRITERS=8 \
|
||||
./target/ci/meridian-relay > /tmp/meridian-relay-default-admission.log 2>&1 &
|
||||
echo $! > /tmp/meridian-relay-default-admission.pid
|
||||
for attempt in $(seq 1 60); do
|
||||
if ! kill -0 "$(cat /tmp/codebase-chat-relay-default-admission.pid)" 2>/dev/null; then
|
||||
cat /tmp/codebase-chat-relay-default-admission.log
|
||||
if ! kill -0 "$(cat /tmp/meridian-relay-default-admission.pid)" 2>/dev/null; then
|
||||
cat /tmp/meridian-relay-default-admission.log
|
||||
exit 1
|
||||
fi
|
||||
if [[ "$(curl -s -o /dev/null -w '%{http_code}' -H 'Host: localhost:3000' http://127.0.0.1:3002/_readiness || true)" == 200 ]]; then
|
||||
|
|
@ -816,12 +816,12 @@ jobs:
|
|||
fi
|
||||
sleep 1
|
||||
done
|
||||
cat /tmp/codebase-chat-relay-default-admission.log
|
||||
cat /tmp/meridian-relay-default-admission.log
|
||||
exit 1
|
||||
- name: Relay E2E tests
|
||||
run: |
|
||||
cargo test -p codebase-chat-test-client --test e2e_persona --test e2e_nostr_interop -- --ignored --nocapture
|
||||
cargo test -p codebase-chat-test-client --test e2e_relay -- --ignored --nocapture
|
||||
cargo test -p meridian-test-client --test e2e_persona --test e2e_nostr_interop -- --ignored --nocapture
|
||||
cargo test -p meridian-test-client --test e2e_relay -- --ignored --nocapture
|
||||
env:
|
||||
RELAY_URL: ws://localhost:3000
|
||||
RELAY_HTTP_URL_A: http://127.0.0.1:3000
|
||||
|
|
@ -829,32 +829,32 @@ jobs:
|
|||
RELAY_HTTP_URL_B: http://127.0.0.1:3001
|
||||
RELAY_DEFAULT_ADMISSION_URL: ws://127.0.0.1:3002
|
||||
RELAY_AUTHORITY: localhost:3000
|
||||
CODEBASE_CHAT_E2E_GIT_COMMUNITY_ID: 00000000-0000-4000-8000-00000000c0de
|
||||
MERIDIAN_E2E_GIT_COMMUNITY_ID: 00000000-0000-4000-8000-00000000c0de
|
||||
GIT_CREDENTIAL_NOSTR_BIN: ${{ github.workspace }}/target/ci/git-credential-nostr
|
||||
- name: Dedicated subscriber fault matrix
|
||||
run: ./scripts/run-subscriber-fault-matrix.sh
|
||||
env:
|
||||
DATABASE_URL: postgres://codebase_chat:codebase_chat_dev@localhost:5432/codebase_chat
|
||||
DATABASE_URL: postgres://meridian:meridian_dev@localhost:5432/meridian
|
||||
REDIS_URL: redis://localhost:6379
|
||||
RELAY_URL: ws://localhost:3000
|
||||
RELAY_AUTHORITY: localhost:3000
|
||||
RELAY_TRANSPORT_URL_A: ws://127.0.0.1:3000
|
||||
RELAY_HTTP_URL_A: http://127.0.0.1:3000
|
||||
SUBSCRIBER_FAULT_RELAY_BIN: ${{ github.workspace }}/target/ci/codebase-chat-relay
|
||||
SUBSCRIBER_FAULT_PROXY_LOG: /tmp/codebase-chat-subscriber-fault-proxy.log
|
||||
SUBSCRIBER_FAULT_RELAY_LOG: /tmp/codebase-chat-subscriber-fault-relay.log
|
||||
SUBSCRIBER_FAULT_RELAY_BIN: ${{ github.workspace }}/target/ci/meridian-relay
|
||||
SUBSCRIBER_FAULT_PROXY_LOG: /tmp/meridian-subscriber-fault-proxy.log
|
||||
SUBSCRIBER_FAULT_RELAY_LOG: /tmp/meridian-subscriber-fault-relay.log
|
||||
- name: Scheduled relay E2E inventory lane
|
||||
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
|
||||
run: |
|
||||
while IFS= read -r test_binary; do
|
||||
cargo test -p codebase-chat-test-client --test "$test_binary" -- --ignored --nocapture
|
||||
cargo test -p meridian-test-client --test "$test_binary" -- --ignored --nocapture
|
||||
done < <(node scripts/check-relay-e2e-inventory.mjs --list scheduled)
|
||||
env:
|
||||
RELAY_URL: ws://localhost:3000
|
||||
RELAY_URL_B: ws://127.0.0.1:3001
|
||||
RELAY_HTTP_URL_B: http://127.0.0.1:3001
|
||||
RELAY_AUTHORITY: localhost:3000
|
||||
CODEBASE_CHAT_E2E_GIT_COMMUNITY_ID: 00000000-0000-4000-8000-00000000c0de
|
||||
MERIDIAN_E2E_GIT_COMMUNITY_ID: 00000000-0000-4000-8000-00000000c0de
|
||||
GIT_CREDENTIAL_NOSTR_BIN: ${{ github.workspace }}/target/ci/git-credential-nostr
|
||||
- name: Upload relay logs
|
||||
if: failure()
|
||||
|
|
@ -862,11 +862,11 @@ jobs:
|
|||
with:
|
||||
name: relay-e2e-artifacts
|
||||
path: |
|
||||
/tmp/codebase-chat-relay.log
|
||||
/tmp/codebase-chat-relay-b.log
|
||||
/tmp/codebase-chat-relay-default-admission.log
|
||||
/tmp/codebase-chat-subscriber-fault-proxy.log
|
||||
/tmp/codebase-chat-subscriber-fault-relay.log
|
||||
/tmp/meridian-relay.log
|
||||
/tmp/meridian-relay-b.log
|
||||
/tmp/meridian-relay-default-admission.log
|
||||
/tmp/meridian-subscriber-fault-proxy.log
|
||||
/tmp/meridian-subscriber-fault-relay.log
|
||||
if-no-files-found: ignore
|
||||
|
||||
web:
|
||||
|
|
@ -1032,10 +1032,10 @@ jobs:
|
|||
CARGO_CMD: ${{ github.event_name == 'pull_request' && 'check' || 'build' }}
|
||||
run: |
|
||||
cross "$CARGO_CMD" --release --target "$TARGET" \
|
||||
-p codebase-chat-relay \
|
||||
-p codebase-chat-acp \
|
||||
-p codebase-chat-agent \
|
||||
-p codebase-chat-dev-mcp \
|
||||
-p meridian-relay \
|
||||
-p meridian-acp \
|
||||
-p meridian-agent \
|
||||
-p meridian-dev-mcp \
|
||||
-p git-credential-nostr \
|
||||
-p git-sign-nostr
|
||||
|
||||
|
|
@ -1073,19 +1073,19 @@ jobs:
|
|||
shell: bash
|
||||
run: |
|
||||
mkdir -p desktop/src-tauri/binaries
|
||||
for bin in codebase-chat-acp codebase-chat-agent codebase-chat-dev-mcp git-credential-nostr codebase-chat; do
|
||||
for bin in meridian-acp meridian-agent meridian-dev-mcp git-credential-nostr meridian; do
|
||||
touch "desktop/src-tauri/binaries/${bin}-${TARGET}.exe"
|
||||
done
|
||||
- name: Clippy (workspace)
|
||||
run: cargo clippy --workspace --all-targets --target $env:TARGET -- -D warnings
|
||||
- name: Check (workspace)
|
||||
run: cargo check --workspace --all-targets --target $env:TARGET
|
||||
- name: Test (codebase-chat-dev-mcp)
|
||||
# The Windows-only bash resolver lives in codebase-chat-dev-mcp; its unit tests
|
||||
- name: Test (meridian-dev-mcp)
|
||||
# The Windows-only bash resolver lives in meridian-dev-mcp; its unit tests
|
||||
# only gate if this crate is tested ON Windows.
|
||||
# Serial: windows_resolver_tests mutate process-global env
|
||||
# (CODEBASE_CHAT_SHELL/GIT_BASH/SystemRoot) that SharedState::new reads.
|
||||
run: cargo test -p codebase-chat-dev-mcp --target $env:TARGET -- --test-threads=1
|
||||
# (MERIDIAN_SHELL/GIT_BASH/SystemRoot) that SharedState::new reads.
|
||||
run: cargo test -p meridian-dev-mcp --target $env:TARGET -- --test-threads=1
|
||||
# Smoke-test the new host-prereq contract: Git for Windows (which provides
|
||||
# bash) is available on the runner, a shell command round-trips, and bash
|
||||
# does NOT resolve from System32 (so WSL's launcher is never picked up).
|
||||
|
|
@ -1145,11 +1145,11 @@ jobs:
|
|||
run: |
|
||||
TARGET=$(rustc -vV | sed -n 's|host: ||p')
|
||||
mkdir -p desktop/src-tauri/binaries
|
||||
touch "desktop/src-tauri/binaries/codebase-chat-acp-$TARGET"
|
||||
touch "desktop/src-tauri/binaries/codebase-chat-agent-$TARGET"
|
||||
touch "desktop/src-tauri/binaries/codebase-chat-dev-mcp-$TARGET"
|
||||
touch "desktop/src-tauri/binaries/meridian-acp-$TARGET"
|
||||
touch "desktop/src-tauri/binaries/meridian-agent-$TARGET"
|
||||
touch "desktop/src-tauri/binaries/meridian-dev-mcp-$TARGET"
|
||||
touch "desktop/src-tauri/binaries/git-credential-nostr-$TARGET"
|
||||
touch "desktop/src-tauri/binaries/codebase-chat-$TARGET"
|
||||
touch "desktop/src-tauri/binaries/meridian-$TARGET"
|
||||
# Mesh rev is derived from Cargo.lock so a dependency bump needs no
|
||||
# lockstep edit here; the cache key tracks it automatically.
|
||||
- name: Resolve mesh-llm rev
|
||||
|
|
|
|||
68
.github/workflows/control-plane.yml
vendored
68
.github/workflows/control-plane.yml
vendored
|
|
@ -8,7 +8,7 @@ on:
|
|||
paths:
|
||||
- "crates/**"
|
||||
- "migrations/**"
|
||||
- "deploy/charts/codebase-chat-control-plane/**"
|
||||
- "deploy/charts/meridian-control-plane/**"
|
||||
- "deploy/compose/**"
|
||||
- "Dockerfile.control-plane"
|
||||
- ".dockerignore"
|
||||
|
|
@ -25,7 +25,7 @@ on:
|
|||
paths:
|
||||
- "crates/**"
|
||||
- "migrations/**"
|
||||
- "deploy/charts/codebase-chat-control-plane/**"
|
||||
- "deploy/charts/meridian-control-plane/**"
|
||||
- "deploy/compose/**"
|
||||
- "Dockerfile.control-plane"
|
||||
- ".dockerignore"
|
||||
|
|
@ -41,7 +41,7 @@ on:
|
|||
permissions: {}
|
||||
|
||||
env:
|
||||
CONTROL_PLANE_IMAGE: ghcr.io/block/codebase-chat-control-plane
|
||||
CONTROL_PLANE_IMAGE: registry.r2d2.office.ilab.zone/meridian-control-plane
|
||||
|
||||
jobs:
|
||||
chart:
|
||||
|
|
@ -53,7 +53,7 @@ jobs:
|
|||
with: { version: v3.16.4 }
|
||||
# Asserts, among other things, that the dev identity provider cannot be
|
||||
# selected through the chart.
|
||||
- run: deploy/charts/codebase-chat-control-plane/tests/render.sh
|
||||
- run: deploy/charts/meridian-control-plane/tests/render.sh
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
|
@ -62,25 +62,25 @@ jobs:
|
|||
postgres:
|
||||
image: postgres:17-alpine
|
||||
env:
|
||||
POSTGRES_USER: codebase_chat
|
||||
POSTGRES_PASSWORD: codebase_chat_dev
|
||||
POSTGRES_USER: meridian
|
||||
POSTGRES_PASSWORD: meridian_dev
|
||||
POSTGRES_DB: postgres
|
||||
ports: ["5432:5432"]
|
||||
options: >-
|
||||
--health-cmd "pg_isready -U codebase_chat"
|
||||
--health-cmd "pg_isready -U meridian"
|
||||
--health-interval 5s
|
||||
--health-timeout 5s
|
||||
--health-retries 10
|
||||
steps:
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
||||
- uses: cashapp/activate-hermit@cea9af7913204a965fd488637a8d1811bba2e616 # v1
|
||||
- run: cargo fmt --check -p codebase-chat-control-plane
|
||||
- run: cargo clippy -p codebase-chat-control-plane --all-targets -- -D warnings
|
||||
- run: cargo fmt --check -p meridian-control-plane
|
||||
- run: cargo clippy -p meridian-control-plane --all-targets -- -D warnings
|
||||
# The integration suite SKIPs without a database, so the URL is what makes
|
||||
# this job meaningful rather than a silent pass.
|
||||
- run: cargo test -p codebase-chat-control-plane
|
||||
- run: cargo test -p meridian-control-plane
|
||||
env:
|
||||
CODEBASE_CHAT_TEST_DATABASE_URL: postgres://codebase_chat:codebase_chat_dev@localhost:5432/postgres
|
||||
MERIDIAN_TEST_DATABASE_URL: postgres://meridian:meridian_dev@localhost:5432/postgres
|
||||
|
||||
browser-e2e:
|
||||
runs-on: ubuntu-latest
|
||||
|
|
@ -95,7 +95,7 @@ jobs:
|
|||
run: docker compose up -d postgres control-plane-db-init dragonfly minio minio-init
|
||||
- name: Wait for backing services
|
||||
run: |
|
||||
for container in codebase-chat-postgres codebase-chat-dragonfly codebase-chat-minio; do
|
||||
for container in meridian-postgres meridian-dragonfly meridian-minio; do
|
||||
for attempt in $(seq 1 60); do
|
||||
status=$(docker inspect --format='{{.State.Health.Status}}' "$container" 2>/dev/null || true)
|
||||
[ "$status" = healthy ] && break
|
||||
|
|
@ -106,26 +106,26 @@ jobs:
|
|||
exit 1
|
||||
}
|
||||
done
|
||||
docker wait codebase-chat-control-plane-db-init
|
||||
docker wait meridian-control-plane-db-init
|
||||
- name: Build relay and control plane
|
||||
run: cargo build -p codebase-chat-relay -p codebase-chat-control-plane
|
||||
run: cargo build -p meridian-relay -p meridian-control-plane
|
||||
- name: Start relay and control plane
|
||||
run: |
|
||||
secret=0000000000000000000000000000000000000000000000000000000000000003
|
||||
pubkey=$(CODEBASE_CHAT_CONTROL_RELAY_OPERATOR_SECRET_KEY="$secret" \
|
||||
target/debug/codebase-chat-control-plane --print-operator-pubkey)
|
||||
pubkey=$(MERIDIAN_CONTROL_RELAY_OPERATOR_SECRET_KEY="$secret" \
|
||||
target/debug/meridian-control-plane --print-operator-pubkey)
|
||||
|
||||
nohup env \
|
||||
DATABASE_URL=postgres://codebase_chat:codebase_chat_dev@localhost:5432/codebase_chat \
|
||||
DATABASE_URL=postgres://meridian:meridian_dev@localhost:5432/meridian \
|
||||
REDIS_URL=redis://localhost:6379 \
|
||||
RELAY_URL=ws://localhost:3000 \
|
||||
CODEBASE_CHAT_BIND_ADDR=0.0.0.0:3000 \
|
||||
CODEBASE_CHAT_AUTO_MIGRATE=true \
|
||||
CODEBASE_CHAT_REQUIRE_AUTH_TOKEN=false \
|
||||
CODEBASE_CHAT_RECONCILE_CHANNELS=false \
|
||||
MERIDIAN_BIND_ADDR=0.0.0.0:3000 \
|
||||
MERIDIAN_AUTO_MIGRATE=true \
|
||||
MERIDIAN_REQUIRE_AUTH_TOKEN=false \
|
||||
MERIDIAN_RECONCILE_CHANNELS=false \
|
||||
RELAY_OPERATOR_PUBKEYS="$pubkey" \
|
||||
RELAY_OPERATOR_API_ORIGIN=http://127.0.0.1:3000 \
|
||||
target/debug/codebase-chat-relay >/tmp/control-plane-e2e-relay.log 2>&1 &
|
||||
target/debug/meridian-relay >/tmp/control-plane-e2e-relay.log 2>&1 &
|
||||
|
||||
for attempt in $(seq 1 60); do
|
||||
[ "$(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:3000/_readiness || true)" = 200 ] && break
|
||||
|
|
@ -136,18 +136,18 @@ jobs:
|
|||
exit 1
|
||||
}
|
||||
|
||||
export CODEBASE_CHAT_CONTROL_DATABASE_URL=postgres://codebase_chat:codebase_chat_dev@localhost:5432/codebase_chat_control_plane
|
||||
export CODEBASE_CHAT_CONTROL_RUNTIME_DATABASE_ROLE=codebase_chat
|
||||
export CODEBASE_CHAT_CONTROL_RELAY_OPERATOR_SECRET_KEY="$secret"
|
||||
export CODEBASE_CHAT_CONTROL_RELAY_OPERATOR_API_ORIGIN=http://127.0.0.1:3000
|
||||
export CODEBASE_CHAT_CONTROL_PUBLIC_ORIGIN=http://127.0.0.1:8090
|
||||
export CODEBASE_CHAT_CONTROL_COMMUNITY_HOST_SUFFIX=communities.localtest.me
|
||||
export CODEBASE_CHAT_CONTROL_COMMUNITY_HOST_PORT=3000
|
||||
export CODEBASE_CHAT_CONTROL_RELAY_SCHEME=ws
|
||||
export CODEBASE_CHAT_CONTROL_IDENTITY_PROVIDER=dev
|
||||
export CODEBASE_CHAT_CONTROL_ALLOW_DEV_LOGIN=1
|
||||
target/debug/codebase-chat-control-plane --migrate-only
|
||||
nohup target/debug/codebase-chat-control-plane >/tmp/control-plane-e2e.log 2>&1 &
|
||||
export MERIDIAN_CONTROL_DATABASE_URL=postgres://meridian:meridian_dev@localhost:5432/meridian_control_plane
|
||||
export MERIDIAN_CONTROL_RUNTIME_DATABASE_ROLE=meridian
|
||||
export MERIDIAN_CONTROL_RELAY_OPERATOR_SECRET_KEY="$secret"
|
||||
export MERIDIAN_CONTROL_RELAY_OPERATOR_API_ORIGIN=http://127.0.0.1:3000
|
||||
export MERIDIAN_CONTROL_PUBLIC_ORIGIN=http://127.0.0.1:8090
|
||||
export MERIDIAN_CONTROL_COMMUNITY_HOST_SUFFIX=communities.localtest.me
|
||||
export MERIDIAN_CONTROL_COMMUNITY_HOST_PORT=3000
|
||||
export MERIDIAN_CONTROL_RELAY_SCHEME=ws
|
||||
export MERIDIAN_CONTROL_IDENTITY_PROVIDER=dev
|
||||
export MERIDIAN_CONTROL_ALLOW_DEV_LOGIN=1
|
||||
target/debug/meridian-control-plane --migrate-only
|
||||
nohup target/debug/meridian-control-plane >/tmp/control-plane-e2e.log 2>&1 &
|
||||
for attempt in $(seq 1 60); do
|
||||
[ "$(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8091/health/ready || true)" = 200 ] && exit 0
|
||||
sleep 1
|
||||
|
|
|
|||
34
.github/workflows/docker.yml
vendored
34
.github/workflows/docker.yml
vendored
|
|
@ -1,6 +1,6 @@
|
|||
name: Docker image
|
||||
|
||||
# Builds and publishes the public Codebase Chat relay images as ghcr.io/codebase/codebase-chat.
|
||||
# Builds and publishes the public Meridian relay images as registry.r2d2.office.ilab.zone/meridian.
|
||||
# Normal tags contain stripped binaries; matching debug-* tags contain the same
|
||||
# optimized binaries with line-table debug information for native profilers.
|
||||
#
|
||||
|
|
@ -13,7 +13,7 @@ name: Docker image
|
|||
# Versioning: the relay is versioned independently of the desktop app via
|
||||
# its own `relay-v*` tags (see `just release-relay`). Desktop `v*` tags and
|
||||
# agent `sprig-v*` tags do NOT publish this image — only `relay-v*` does, so
|
||||
# the relay image version tracks crates/codebase-chat-relay/Cargo.toml, never desktop.
|
||||
# the relay image version tracks crates/meridian-relay/Cargo.toml, never desktop.
|
||||
#
|
||||
# Triggers:
|
||||
# - push to main → :main + :sha-<7>
|
||||
|
|
@ -76,7 +76,7 @@ env:
|
|||
# Single source of truth for the image name. Set GHCR_IMAGE as a repo
|
||||
# variable to override (e.g., for forks that want to push to their own
|
||||
# namespace without forking this file).
|
||||
IMAGE_NAME: ${{ vars.GHCR_IMAGE != '' && vars.GHCR_IMAGE || 'ghcr.io/codebase/codebase-chat' }}
|
||||
IMAGE_NAME: ${{ vars.GHCR_IMAGE != '' && vars.GHCR_IMAGE || 'registry.r2d2.office.ilab.zone/meridian' }}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
|
@ -159,8 +159,8 @@ jobs:
|
|||
type=semver,pattern={{major}}.{{minor}},match=^relay-v(.*)$,value=${{ inputs.version }}
|
||||
type=semver,pattern={{major}},match=^relay-v(.*)$,value=${{ inputs.version }}
|
||||
labels: |
|
||||
org.opencontainers.image.title=Codebase Chat
|
||||
org.opencontainers.image.description=WebSocket relay server for the Codebase Chat communications platform
|
||||
org.opencontainers.image.title=Meridian
|
||||
org.opencontainers.image.description=WebSocket relay server for the Meridian communications platform
|
||||
org.opencontainers.image.licenses=Apache-2.0
|
||||
|
||||
- name: Build and push release image by digest
|
||||
|
|
@ -310,7 +310,7 @@ jobs:
|
|||
|
||||
- name: Attest provenance for the merged image
|
||||
# Sigstore-signed in-toto attestation, verifiable with:
|
||||
# gh attestation verify oci://ghcr.io/codebase/codebase-chat:<tag> --owner block
|
||||
# gh attestation verify oci://registry.r2d2.office.ilab.zone/meridian:<tag> --owner block
|
||||
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1
|
||||
with:
|
||||
subject-name: ${{ env.IMAGE_NAME }}
|
||||
|
|
@ -387,10 +387,10 @@ jobs:
|
|||
id: meta
|
||||
uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6.1.0
|
||||
with:
|
||||
images: ghcr.io/block/codebase-chat-push-gateway
|
||||
images: registry.r2d2.office.ilab.zone/meridian-push-gateway
|
||||
labels: |
|
||||
org.opencontainers.image.title=Codebase Chat Push Gateway
|
||||
org.opencontainers.image.description=Capability-gated APNs last hop for Codebase Chat
|
||||
org.opencontainers.image.title=Meridian Push Gateway
|
||||
org.opencontainers.image.description=Capability-gated APNs last hop for Meridian
|
||||
org.opencontainers.image.licenses=Apache-2.0
|
||||
- name: Build and push by digest
|
||||
id: build
|
||||
|
|
@ -400,9 +400,9 @@ jobs:
|
|||
file: ./Dockerfile.push-gateway
|
||||
platforms: ${{ matrix.platform }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
outputs: type=image,name=ghcr.io/block/codebase-chat-push-gateway,push-by-digest=true,name-canonical=true,push=${{ github.event_name != 'pull_request' }}
|
||||
cache-from: type=registry,ref=ghcr.io/block/codebase-chat-push-gateway-buildcache:${{ matrix.arch }}
|
||||
cache-to: ${{ (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && format('type=registry,ref=ghcr.io/block/codebase-chat-push-gateway-buildcache:{0},mode=max,compression=zstd', matrix.arch) || '' }}
|
||||
outputs: type=image,name=registry.r2d2.office.ilab.zone/meridian-push-gateway,push-by-digest=true,name-canonical=true,push=${{ github.event_name != 'pull_request' }}
|
||||
cache-from: type=registry,ref=registry.r2d2.office.ilab.zone/meridian-push-gateway-buildcache:${{ matrix.arch }}
|
||||
cache-to: ${{ (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && format('type=registry,ref=registry.r2d2.office.ilab.zone/meridian-push-gateway-buildcache:{0},mode=max,compression=zstd', matrix.arch) || '' }}
|
||||
- name: Export digest
|
||||
if: github.event_name != 'pull_request'
|
||||
env:
|
||||
|
|
@ -447,7 +447,7 @@ jobs:
|
|||
id: meta
|
||||
uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6.1.0
|
||||
with:
|
||||
images: ghcr.io/block/codebase-chat-push-gateway
|
||||
images: registry.r2d2.office.ilab.zone/meridian-push-gateway
|
||||
tags: |
|
||||
type=ref,event=branch,enable=${{ github.event_name != 'workflow_dispatch' || inputs.version == '' }}
|
||||
type=sha,prefix=sha-,format=short,enable=${{ github.event_name != 'workflow_dispatch' || inputs.version == '' }}
|
||||
|
|
@ -461,7 +461,7 @@ jobs:
|
|||
run: |
|
||||
set -euo pipefail
|
||||
tags=(); while IFS= read -r tag; do [ -n "$tag" ] && tags+=("-t" "$tag"); done <<< "$META_TAGS"
|
||||
digests=(); for digest in *; do digests+=("ghcr.io/block/codebase-chat-push-gateway@sha256:${digest}"); done
|
||||
digests=(); for digest in *; do digests+=("registry.r2d2.office.ilab.zone/meridian-push-gateway@sha256:${digest}"); done
|
||||
docker buildx imagetools create "${tags[@]}" "${digests[@]}"
|
||||
first_tag=$(echo "$META_TAGS" | head -n1)
|
||||
digest=$(docker buildx imagetools inspect "$first_tag" --format '{{json .Manifest}}' | jq -r '.digest')
|
||||
|
|
@ -469,7 +469,7 @@ jobs:
|
|||
- name: Attest gateway image provenance
|
||||
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1
|
||||
with:
|
||||
subject-name: ghcr.io/block/codebase-chat-push-gateway
|
||||
subject-name: registry.r2d2.office.ilab.zone/meridian-push-gateway
|
||||
subject-digest: ${{ steps.manifest.outputs.digest }}
|
||||
push-to-registry: true
|
||||
- name: Gateway publication summary
|
||||
|
|
@ -479,7 +479,7 @@ jobs:
|
|||
run: |
|
||||
set -euo pipefail
|
||||
{
|
||||
echo "### Published \`ghcr.io/block/codebase-chat-push-gateway\`"
|
||||
echo "### Published \`registry.r2d2.office.ilab.zone/meridian-push-gateway\`"
|
||||
echo
|
||||
printf "**Digest:** \`%s\`\n" "$GATEWAY_DIGEST"
|
||||
echo
|
||||
|
|
@ -490,6 +490,6 @@ jobs:
|
|||
echo
|
||||
echo 'Verify provenance before deployment:'
|
||||
echo "\`\`\`"
|
||||
printf 'gh attestation verify oci://ghcr.io/block/codebase-chat-push-gateway@%s --owner block\n' "$GATEWAY_DIGEST"
|
||||
printf 'gh attestation verify oci://registry.r2d2.office.ilab.zone/meridian-push-gateway@%s --owner block\n' "$GATEWAY_DIGEST"
|
||||
echo "\`\`\`"
|
||||
} >> "$GITHUB_STEP_SUMMARY"
|
||||
|
|
|
|||
46
.github/workflows/helm-chart.yml
vendored
46
.github/workflows/helm-chart.yml
vendored
|
|
@ -36,8 +36,8 @@ on:
|
|||
tags: ["chart-v[0-9]*"]
|
||||
pull_request:
|
||||
paths:
|
||||
- "deploy/charts/codebase-chat/**"
|
||||
- "deploy/charts/codebase-chat-push-gateway/**"
|
||||
- "deploy/charts/meridian/**"
|
||||
- "deploy/charts/meridian-push-gateway/**"
|
||||
- ".github/workflows/helm-chart.yml"
|
||||
- "ct.yaml"
|
||||
|
||||
|
|
@ -46,11 +46,11 @@ permissions: {}
|
|||
|
||||
env:
|
||||
# Single source of truth for the OCI chart repository (helm appends the chart
|
||||
# name `codebase-chat`, yielding oci://ghcr.io/codebase/codebase-chat/charts/codebase-chat, which is exactly
|
||||
# the install ref documented in deploy/charts/codebase-chat/README.md). Set
|
||||
# name `meridian`, yielding oci://registry.r2d2.office.ilab.zone/meridian/charts/meridian, which is exactly
|
||||
# the install ref documented in deploy/charts/meridian/README.md). Set
|
||||
# GHCR_CHART_REPO as a repo variable to override (e.g., forks pushing to their
|
||||
# own namespace without editing this file) — mirrors docker.yml's GHCR_IMAGE.
|
||||
CHART_REPO: ${{ vars.GHCR_CHART_REPO != '' && vars.GHCR_CHART_REPO || 'oci://ghcr.io/codebase/codebase-chat/charts' }}
|
||||
CHART_REPO: ${{ vars.GHCR_CHART_REPO != '' && vars.GHCR_CHART_REPO || 'oci://registry.r2d2.office.ilab.zone/meridian/charts' }}
|
||||
|
||||
jobs:
|
||||
lint-and-unittest:
|
||||
|
|
@ -84,31 +84,31 @@ jobs:
|
|||
uses: helm/chart-testing-action@0d28d3144d3a25ea2cc349d6e59901c4ff469b3b # v2.7.0
|
||||
|
||||
- name: Build chart dependencies
|
||||
run: helm dependency build deploy/charts/codebase-chat
|
||||
run: helm dependency build deploy/charts/meridian
|
||||
|
||||
- name: Push gateway chart lint + render guard
|
||||
run: deploy/charts/codebase-chat-push-gateway/tests/render.sh
|
||||
run: deploy/charts/meridian-push-gateway/tests/render.sh
|
||||
|
||||
- name: ct lint
|
||||
run: ct lint --config ct.yaml --all
|
||||
|
||||
- name: helm-unittest
|
||||
run: helm unittest deploy/charts/codebase-chat
|
||||
run: helm unittest deploy/charts/meridian
|
||||
|
||||
- name: Prometheus alert semantics
|
||||
run: deploy/charts/codebase-chat/tests/prometheus-rules-test.sh
|
||||
run: deploy/charts/meridian/tests/prometheus-rules-test.sh
|
||||
|
||||
- name: helm template (render every fixture)
|
||||
run: |
|
||||
set -euo pipefail
|
||||
for f in deploy/charts/codebase-chat/ci/*-values.yaml deploy/charts/codebase-chat/tests/fixtures/*-values.yaml; do
|
||||
for f in deploy/charts/meridian/ci/*-values.yaml deploy/charts/meridian/tests/fixtures/*-values.yaml; do
|
||||
echo "::group::render $f"
|
||||
helm template codebase-chat deploy/charts/codebase-chat -f "$f"
|
||||
helm template meridian deploy/charts/meridian -f "$f"
|
||||
echo "::endgroup::"
|
||||
done
|
||||
|
||||
install-on-kind:
|
||||
# Full end-to-end install requires the public ghcr.io/codebase/codebase-chat image to
|
||||
# Full end-to-end install requires the public registry.r2d2.office.ilab.zone/meridian image to
|
||||
# exist and to embed Max's startup migrations. Runs only after Sami's
|
||||
# image PR merges (`workflow_dispatch`) or on a schedule once main carries
|
||||
# both prerequisites. Render/lint above is the per-PR signal.
|
||||
|
|
@ -146,10 +146,10 @@ jobs:
|
|||
node_image: kindest/node:v1.31.0
|
||||
|
||||
- name: Build chart dependencies
|
||||
run: helm dependency build deploy/charts/codebase-chat
|
||||
run: helm dependency build deploy/charts/meridian
|
||||
|
||||
- name: ct install (quickstart profile)
|
||||
run: ct install --config ct.yaml --charts deploy/charts/codebase-chat --helm-extra-args "--timeout 600s"
|
||||
run: ct install --config ct.yaml --charts deploy/charts/meridian --helm-extra-args "--timeout 600s"
|
||||
|
||||
publish:
|
||||
# Packages the chart and pushes it to GHCR as an OCI artifact. Fires only on
|
||||
|
|
@ -210,7 +210,7 @@ jobs:
|
|||
# The tag is the source of truth, but the published artifact's version
|
||||
# comes from Chart.yaml — they must agree or we'd publish a mislabeled
|
||||
# chart. Fail loudly on drift rather than silently shipping a mismatch.
|
||||
chart_version="$(helm show chart deploy/charts/codebase-chat | awk '/^version:/ {print $2}')"
|
||||
chart_version="$(helm show chart deploy/charts/meridian | awk '/^version:/ {print $2}')"
|
||||
if [ "$chart_version" != "$version" ]; then
|
||||
echo "::error::Tag version '$version' != Chart.yaml version '$chart_version'. Bump Chart.yaml to match the tag."
|
||||
exit 1
|
||||
|
|
@ -226,10 +226,10 @@ jobs:
|
|||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build chart dependencies
|
||||
run: helm dependency build deploy/charts/codebase-chat
|
||||
run: helm dependency build deploy/charts/meridian
|
||||
|
||||
- name: Package chart
|
||||
run: helm package deploy/charts/codebase-chat --destination dist
|
||||
run: helm package deploy/charts/meridian --destination dist
|
||||
|
||||
- name: Push chart to GHCR
|
||||
env:
|
||||
|
|
@ -237,23 +237,23 @@ jobs:
|
|||
VERSION: ${{ steps.ver.outputs.version }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
helm push "dist/codebase-chat-${VERSION}.tgz" "$CHART_REPO"
|
||||
helm push "dist/meridian-${VERSION}.tgz" "$CHART_REPO"
|
||||
|
||||
- name: Summary
|
||||
env:
|
||||
CHART_REPO: ${{ env.CHART_REPO }}
|
||||
VERSION: ${{ steps.ver.outputs.version }}
|
||||
run: |
|
||||
# CHART_REPO is oci://ghcr.io/codebase/codebase-chat/charts; helm push appends the
|
||||
# chart name, so the install ref is .../charts/codebase-chat.
|
||||
INSTALL_REF="${CHART_REPO}/codebase-chat"
|
||||
# CHART_REPO is oci://registry.r2d2.office.ilab.zone/meridian/charts; helm push appends the
|
||||
# chart name, so the install ref is .../charts/meridian.
|
||||
INSTALL_REF="${CHART_REPO}/meridian"
|
||||
{
|
||||
echo "### Published chart \`codebase-chat\` \`${VERSION}\`"
|
||||
echo "### Published chart \`meridian\` \`${VERSION}\`"
|
||||
echo
|
||||
echo "**OCI ref:** \`${INSTALL_REF}:${VERSION}\`"
|
||||
echo
|
||||
echo "Install:"
|
||||
echo '```'
|
||||
echo "helm install codebase-chat ${INSTALL_REF} --version ${VERSION}"
|
||||
echo "helm install meridian ${INSTALL_REF} --version ${VERSION}"
|
||||
echo '```'
|
||||
} >> "$GITHUB_STEP_SUMMARY"
|
||||
|
|
|
|||
6
.github/workflows/linux-canary.yml
vendored
6
.github/workflows/linux-canary.yml
vendored
|
|
@ -19,7 +19,7 @@ permissions:
|
|||
jobs:
|
||||
build:
|
||||
name: Build Linux canary
|
||||
if: github.repository == 'codebase/codebase-chat'
|
||||
if: github.repository == 'r2d2/meridian'
|
||||
runs-on: ubuntu-latest
|
||||
container: ubuntu:24.04@sha256:4fbb8e6a8395de5a7550b33509421a2bafbc0aab6c06ba2cef9ebffbc7092d90
|
||||
timeout-minutes: 60
|
||||
|
|
@ -166,7 +166,7 @@ jobs:
|
|||
|
||||
- name: Build sidecars
|
||||
run: |
|
||||
cargo build --release -p codebase-chat-acp -p codebase-chat-agent -p codebase-chat-dev-mcp -p git-credential-nostr -p codebase-chat-cli
|
||||
cargo build --release -p meridian-acp -p meridian-agent -p meridian-dev-mcp -p git-credential-nostr -p meridian-cli
|
||||
./scripts/bundle-sidecars.sh
|
||||
|
||||
- name: Build Linux Tauri app
|
||||
|
|
@ -219,7 +219,7 @@ jobs:
|
|||
- name: Upload Linux canary packages
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
with:
|
||||
name: codebase-chat-linux-canary-${{ github.sha }}
|
||||
name: meridian-linux-canary-${{ github.sha }}
|
||||
path: |
|
||||
${{ steps.artifacts.outputs.deb }}
|
||||
${{ steps.artifacts.outputs.appimage }}
|
||||
|
|
|
|||
10
.github/workflows/mobile-release-candidate.yml
vendored
10
.github/workflows/mobile-release-candidate.yml
vendored
|
|
@ -13,7 +13,7 @@ on:
|
|||
required: true
|
||||
type: string
|
||||
target_sha:
|
||||
description: Exact current codebase/codebase-chat main commit
|
||||
description: Exact current r2d2/meridian main commit
|
||||
required: true
|
||||
type: string
|
||||
|
||||
|
|
@ -47,8 +47,8 @@ jobs:
|
|||
env:
|
||||
REPOSITORY: ${{ github.repository }}
|
||||
run: |
|
||||
if [ "$REPOSITORY" != "codebase/codebase-chat" ]; then
|
||||
echo "::error::Mobile candidate publication is restricted to codebase/codebase-chat"
|
||||
if [ "$REPOSITORY" != "r2d2/meridian" ]; then
|
||||
echo "::error::Mobile candidate publication is restricted to r2d2/meridian"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
|
@ -56,8 +56,8 @@ jobs:
|
|||
id: release-tagger
|
||||
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
|
||||
with:
|
||||
client-id: ${{ vars.CODEBASE_CHAT_RELEASE_TAGGER_CLIENT_ID }}
|
||||
private-key: ${{ secrets.CODEBASE_CHAT_RELEASE_TAGGER_PRIVATE_KEY }}
|
||||
client-id: ${{ vars.MERIDIAN_RELEASE_TAGGER_CLIENT_ID }}
|
||||
private-key: ${{ secrets.MERIDIAN_RELEASE_TAGGER_PRIVATE_KEY }}
|
||||
permission-contents: write
|
||||
|
||||
- name: Publish annotated candidate tag
|
||||
|
|
|
|||
4
.github/workflows/n-minus-one-rollout.yml
vendored
4
.github/workflows/n-minus-one-rollout.yml
vendored
|
|
@ -45,8 +45,8 @@ jobs:
|
|||
for attempt in $(seq 1 90); do
|
||||
postgres_ok=false
|
||||
redis_ok=false
|
||||
docker exec codebase-chat-postgres pg_isready -U codebase_chat -d codebase_chat >/dev/null 2>&1 && postgres_ok=true
|
||||
docker exec codebase-chat-dragonfly redis-cli ping 2>/dev/null | grep -q PONG && redis_ok=true
|
||||
docker exec meridian-postgres pg_isready -U meridian -d meridian >/dev/null 2>&1 && postgres_ok=true
|
||||
docker exec meridian-dragonfly redis-cli ping 2>/dev/null | grep -q PONG && redis_ok=true
|
||||
if [[ "$postgres_ok" == true && "$redis_ok" == true ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
|
|
|||
14
.github/workflows/push-gateway-helm-chart.yml
vendored
14
.github/workflows/push-gateway-helm-chart.yml
vendored
|
|
@ -13,11 +13,11 @@ on:
|
|||
tags: ["push-chart-v[0-9]*"]
|
||||
pull_request:
|
||||
paths:
|
||||
- "deploy/charts/codebase-chat-push-gateway/**"
|
||||
- "deploy/charts/meridian-push-gateway/**"
|
||||
- ".github/workflows/push-gateway-helm-chart.yml"
|
||||
permissions: {}
|
||||
env:
|
||||
CHART_REPO: oci://ghcr.io/codebase/codebase-chat/charts
|
||||
CHART_REPO: oci://registry.r2d2.office.ilab.zone/meridian/charts
|
||||
jobs:
|
||||
validate:
|
||||
runs-on: ubuntu-latest
|
||||
|
|
@ -29,8 +29,8 @@ jobs:
|
|||
fetch-depth: 0
|
||||
- uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4
|
||||
with: { version: v3.16.4 }
|
||||
- run: deploy/charts/codebase-chat-push-gateway/tests/render.sh
|
||||
- run: deploy/charts/codebase-chat-push-gateway/tests/release-contract.sh
|
||||
- run: deploy/charts/meridian-push-gateway/tests/render.sh
|
||||
- run: deploy/charts/meridian-push-gateway/tests/release-contract.sh
|
||||
publish:
|
||||
if: github.event_name != 'pull_request'
|
||||
needs: validate
|
||||
|
|
@ -54,7 +54,7 @@ jobs:
|
|||
set -euo pipefail
|
||||
version="${INPUT_VERSION:-${REF_NAME#push-chart-v}}"
|
||||
[[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]
|
||||
test "$(helm show chart deploy/charts/codebase-chat-push-gateway | awk '/^version:/ {print $2}')" = "$version"
|
||||
test "$(helm show chart deploy/charts/meridian-push-gateway | awk '/^version:/ {print $2}')" = "$version"
|
||||
if [ -n "$INPUT_VERSION" ]; then
|
||||
test "$(git rev-parse HEAD)" = "$(git rev-parse "refs/tags/push-chart-v${version}^{commit}")"
|
||||
fi
|
||||
|
|
@ -64,5 +64,5 @@ jobs:
|
|||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- run: helm package deploy/charts/codebase-chat-push-gateway --destination dist
|
||||
- run: helm push "dist/codebase-chat-push-gateway-${VERSION}.tgz" "$CHART_REPO"
|
||||
- run: helm package deploy/charts/meridian-push-gateway --destination dist
|
||||
- run: helm push "dist/meridian-push-gateway-${VERSION}.tgz" "$CHART_REPO"
|
||||
|
|
|
|||
104
.github/workflows/release.yml
vendored
104
.github/workflows/release.yml
vendored
|
|
@ -15,7 +15,7 @@ jobs:
|
|||
# create the release objects all four platform jobs upload into.
|
||||
setup:
|
||||
name: Setup
|
||||
if: github.repository == 'codebase/codebase-chat'
|
||||
if: github.repository == 'r2d2/meridian'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
permissions:
|
||||
|
|
@ -70,7 +70,7 @@ jobs:
|
|||
NOTES=$(awk "/^## v${VERSION}\$/{found=1; next} found && /^## v/{exit} found && !/^\$/" CHANGELOG.md)
|
||||
fi
|
||||
if [[ -z "$NOTES" ]]; then
|
||||
NOTES="Codebase Chat Desktop v${VERSION}"
|
||||
NOTES="Meridian Desktop v${VERSION}"
|
||||
fi
|
||||
PRERELEASE_FLAGS=()
|
||||
if [[ "$VERSION" =~ -(test|alpha|beta|rc)([.-]|$) ]]; then
|
||||
|
|
@ -78,7 +78,7 @@ jobs:
|
|||
fi
|
||||
gh release create "v${VERSION}" \
|
||||
--target "$RELEASE_SHA" \
|
||||
--title "Codebase Chat Desktop v${VERSION}" \
|
||||
--title "Meridian Desktop v${VERSION}" \
|
||||
--notes "$NOTES" \
|
||||
"${PRERELEASE_FLAGS[@]}"
|
||||
|
||||
|
|
@ -86,15 +86,15 @@ jobs:
|
|||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
gh release create codebase-chat-desktop-latest \
|
||||
gh release create meridian-desktop-latest \
|
||||
--prerelease \
|
||||
--title "Codebase Chat Desktop Auto-Update" \
|
||||
--title "Meridian Desktop Auto-Update" \
|
||||
--notes "Rolling release for the Tauri auto-updater. Do not download manually — use the versioned release instead." \
|
||||
2>/dev/null || true
|
||||
|
||||
release:
|
||||
name: Release
|
||||
if: github.repository == 'codebase/codebase-chat'
|
||||
if: github.repository == 'r2d2/meridian'
|
||||
runs-on: macos-latest
|
||||
needs: setup
|
||||
timeout-minutes: 60
|
||||
|
|
@ -129,12 +129,12 @@ jobs:
|
|||
- name: Generate release config
|
||||
run: cd desktop && node scripts/build-release-config.mjs
|
||||
env:
|
||||
CODEBASE_CHAT_UPDATER_PUBLIC_KEY: ${{ secrets.CODEBASE_CHAT_UPDATER_PUBLIC_KEY || secrets.SPROUT_UPDATER_PUBLIC_KEY }}
|
||||
CODEBASE_CHAT_UPDATER_ENDPOINT: https://github.com/codebase/codebase-chat/releases/download/codebase-chat-desktop-latest/latest.json
|
||||
MERIDIAN_UPDATER_PUBLIC_KEY: ${{ secrets.MERIDIAN_UPDATER_PUBLIC_KEY || secrets.SPROUT_UPDATER_PUBLIC_KEY }}
|
||||
MERIDIAN_UPDATER_ENDPOINT: https://github.com/r2d2/meridian/releases/download/meridian-desktop-latest/latest.json
|
||||
|
||||
- name: Build sidecars
|
||||
run: |
|
||||
cargo build --release -p codebase-chat-acp -p codebase-chat-agent -p codebase-chat-dev-mcp -p git-credential-nostr -p codebase-chat-cli
|
||||
cargo build --release -p meridian-acp -p meridian-agent -p meridian-dev-mcp -p git-credential-nostr -p meridian-cli
|
||||
./scripts/bundle-sidecars.sh
|
||||
|
||||
# Mesh rev derived from Cargo.lock (no lockstep edit on dep bump); cache key tracks it.
|
||||
|
|
@ -180,8 +180,8 @@ jobs:
|
|||
- name: Build unsigned Tauri app
|
||||
run: cd desktop && pnpm tauri build --verbose --no-sign --features mesh-llm --config src-tauri/tauri.release.conf.json
|
||||
env:
|
||||
CODEBASE_CHAT_UPDATER_PUBLIC_KEY: ${{ secrets.CODEBASE_CHAT_UPDATER_PUBLIC_KEY || secrets.SPROUT_UPDATER_PUBLIC_KEY }}
|
||||
CODEBASE_CHAT_UPDATER_ENDPOINT: https://github.com/codebase/codebase-chat/releases/download/codebase-chat-desktop-latest/latest.json
|
||||
MERIDIAN_UPDATER_PUBLIC_KEY: ${{ secrets.MERIDIAN_UPDATER_PUBLIC_KEY || secrets.SPROUT_UPDATER_PUBLIC_KEY }}
|
||||
MERIDIAN_UPDATER_ENDPOINT: https://github.com/r2d2/meridian/releases/download/meridian-desktop-latest/latest.json
|
||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
|
||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
|
||||
CMAKE_POLICY_VERSION_MINIMUM: "3.5"
|
||||
|
|
@ -220,7 +220,7 @@ jobs:
|
|||
codesign-s3-bucket: ${{ secrets.CODESIGN_S3_BUCKET }}
|
||||
unsigned-artifact-path: ${{ steps.unsigned.outputs.dmg }}
|
||||
entitlements-plist-path: ${{ runner.temp }}/entitlements.plist
|
||||
artifact-name: codebase-chat-${{ github.sha }}-${{ github.run_id }}-arm64
|
||||
artifact-name: meridian-${{ github.sha }}-${{ github.run_id }}-arm64
|
||||
|
||||
- name: Replace DMG and rebuild updater archive
|
||||
env:
|
||||
|
|
@ -241,30 +241,30 @@ jobs:
|
|||
EXTRACT_DIR="${RUNNER_TEMP}/signed-app-extract"
|
||||
rm -rf "$EXTRACT_DIR" && mkdir -p "$EXTRACT_DIR"
|
||||
ditto -x -k "$SIGNED_APP_ZIP" "$EXTRACT_DIR"
|
||||
rm -rf "${APP_DIR}/Codebase Chat.app"
|
||||
cp -R "${EXTRACT_DIR}/Codebase Chat.app" "${APP_DIR}/Codebase Chat.app"
|
||||
rm -rf "${APP_DIR}/Meridian.app"
|
||||
cp -R "${EXTRACT_DIR}/Meridian.app" "${APP_DIR}/Meridian.app"
|
||||
|
||||
# Rebuild the updater archive from the signed .app and re-sign it with the Tauri updater key.
|
||||
rm -f "${APP_DIR}/Codebase Chat.app.tar.gz" "${APP_DIR}/Codebase Chat.app.tar.gz.sig"
|
||||
(cd "$APP_DIR" && tar -czf Codebase Chat.app.tar.gz Codebase Chat.app)
|
||||
TARBALL_ABS="$(pwd)/${APP_DIR}/Codebase Chat.app.tar.gz"
|
||||
rm -f "${APP_DIR}/Meridian.app.tar.gz" "${APP_DIR}/Meridian.app.tar.gz.sig"
|
||||
(cd "$APP_DIR" && tar -czf Meridian.app.tar.gz Meridian.app)
|
||||
TARBALL_ABS="$(pwd)/${APP_DIR}/Meridian.app.tar.gz"
|
||||
(cd desktop && pnpm tauri signer sign "$TARBALL_ABS")
|
||||
|
||||
- name: Verify code signature
|
||||
run: |
|
||||
codesign --verify --deep --strict --verbose=2 \
|
||||
desktop/src-tauri/target/release/bundle/macos/Codebase Chat.app
|
||||
desktop/src-tauri/target/release/bundle/macos/Meridian.app
|
||||
spctl --assess --type execute --verbose=4 \
|
||||
desktop/src-tauri/target/release/bundle/macos/Codebase Chat.app
|
||||
desktop/src-tauri/target/release/bundle/macos/Meridian.app
|
||||
desktop/scripts/verify-macos-entitlements.sh \
|
||||
desktop/src-tauri/target/release/bundle/macos/Codebase Chat.app
|
||||
desktop/src-tauri/target/release/bundle/macos/Meridian.app
|
||||
|
||||
- name: Locate build artifacts
|
||||
id: artifacts
|
||||
run: |
|
||||
BUNDLE_DIR="desktop/src-tauri/target/release/bundle"
|
||||
|
||||
# Find the DMG (Tauri names it CodebaseChat_<version>_<arch>.dmg)
|
||||
# Find the DMG (Tauri names it Meridian_<version>_<arch>.dmg)
|
||||
DMG=$(find "$BUNDLE_DIR/dmg" -name '*.dmg' -type f | head -1)
|
||||
if [[ -z "$DMG" ]]; then
|
||||
echo "::error::No DMG found in $BUNDLE_DIR/dmg"
|
||||
|
|
@ -298,7 +298,7 @@ jobs:
|
|||
- name: Upload updater archive to rolling release
|
||||
if: github.ref == format('refs/tags/v{0}', needs.setup.outputs.version)
|
||||
run: |
|
||||
gh release upload codebase-chat-desktop-latest \
|
||||
gh release upload meridian-desktop-latest \
|
||||
"$ARCHIVE_PATH" \
|
||||
"$SIG_PATH" \
|
||||
--clobber
|
||||
|
|
@ -309,7 +309,7 @@ jobs:
|
|||
|
||||
release-macos-x64:
|
||||
name: Release macOS (Intel)
|
||||
if: github.repository == 'codebase/codebase-chat'
|
||||
if: github.repository == 'r2d2/meridian'
|
||||
runs-on: macos-latest
|
||||
needs: setup
|
||||
timeout-minutes: 60
|
||||
|
|
@ -348,19 +348,19 @@ jobs:
|
|||
- name: Generate release config
|
||||
run: cd desktop && node scripts/build-release-config.mjs
|
||||
env:
|
||||
CODEBASE_CHAT_UPDATER_PUBLIC_KEY: ${{ secrets.CODEBASE_CHAT_UPDATER_PUBLIC_KEY || secrets.SPROUT_UPDATER_PUBLIC_KEY }}
|
||||
CODEBASE_CHAT_UPDATER_ENDPOINT: https://github.com/codebase/codebase-chat/releases/download/codebase-chat-desktop-latest/latest.json
|
||||
MERIDIAN_UPDATER_PUBLIC_KEY: ${{ secrets.MERIDIAN_UPDATER_PUBLIC_KEY || secrets.SPROUT_UPDATER_PUBLIC_KEY }}
|
||||
MERIDIAN_UPDATER_ENDPOINT: https://github.com/r2d2/meridian/releases/download/meridian-desktop-latest/latest.json
|
||||
|
||||
- name: Build sidecars
|
||||
run: |
|
||||
cargo build --release --target "$TARGET" -p codebase-chat-acp -p codebase-chat-agent -p codebase-chat-dev-mcp -p git-credential-nostr -p codebase-chat-cli
|
||||
cargo build --release --target "$TARGET" -p meridian-acp -p meridian-agent -p meridian-dev-mcp -p git-credential-nostr -p meridian-cli
|
||||
./scripts/bundle-sidecars.sh "$TARGET"
|
||||
|
||||
- name: Build unsigned Tauri app
|
||||
run: cd desktop && pnpm tauri build --verbose --no-sign --target "$TARGET" --config src-tauri/tauri.release.conf.json
|
||||
env:
|
||||
CODEBASE_CHAT_UPDATER_PUBLIC_KEY: ${{ secrets.CODEBASE_CHAT_UPDATER_PUBLIC_KEY || secrets.SPROUT_UPDATER_PUBLIC_KEY }}
|
||||
CODEBASE_CHAT_UPDATER_ENDPOINT: https://github.com/codebase/codebase-chat/releases/download/codebase-chat-desktop-latest/latest.json
|
||||
MERIDIAN_UPDATER_PUBLIC_KEY: ${{ secrets.MERIDIAN_UPDATER_PUBLIC_KEY || secrets.SPROUT_UPDATER_PUBLIC_KEY }}
|
||||
MERIDIAN_UPDATER_ENDPOINT: https://github.com/r2d2/meridian/releases/download/meridian-desktop-latest/latest.json
|
||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
|
||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
|
||||
CMAKE_POLICY_VERSION_MINIMUM: "3.5"
|
||||
|
|
@ -396,7 +396,7 @@ jobs:
|
|||
codesign-s3-bucket: ${{ secrets.CODESIGN_S3_BUCKET }}
|
||||
unsigned-artifact-path: ${{ steps.unsigned.outputs.dmg }}
|
||||
entitlements-plist-path: ${{ runner.temp }}/entitlements.plist
|
||||
artifact-name: codebase-chat-${{ github.sha }}-${{ github.run_id }}-x64
|
||||
artifact-name: meridian-${{ github.sha }}-${{ github.run_id }}-x64
|
||||
|
||||
- name: Replace DMG and rebuild updater archive
|
||||
env:
|
||||
|
|
@ -416,18 +416,18 @@ jobs:
|
|||
EXTRACT_DIR="${RUNNER_TEMP}/signed-app-extract-x64"
|
||||
rm -rf "$EXTRACT_DIR" && mkdir -p "$EXTRACT_DIR"
|
||||
ditto -x -k "$SIGNED_APP_ZIP" "$EXTRACT_DIR"
|
||||
rm -rf "${APP_DIR}/Codebase Chat.app"
|
||||
cp -R "${EXTRACT_DIR}/Codebase Chat.app" "${APP_DIR}/Codebase Chat.app"
|
||||
rm -rf "${APP_DIR}/Meridian.app"
|
||||
cp -R "${EXTRACT_DIR}/Meridian.app" "${APP_DIR}/Meridian.app"
|
||||
|
||||
# Rebuild the updater archive from the signed .app and re-sign with the Tauri updater key.
|
||||
rm -f "${APP_DIR}/Codebase Chat.app.tar.gz" "${APP_DIR}/Codebase Chat.app.tar.gz.sig"
|
||||
(cd "$APP_DIR" && tar -czf Codebase Chat.app.tar.gz Codebase Chat.app)
|
||||
TARBALL_ABS="$(pwd)/${APP_DIR}/Codebase Chat.app.tar.gz"
|
||||
rm -f "${APP_DIR}/Meridian.app.tar.gz" "${APP_DIR}/Meridian.app.tar.gz.sig"
|
||||
(cd "$APP_DIR" && tar -czf Meridian.app.tar.gz Meridian.app)
|
||||
TARBALL_ABS="$(pwd)/${APP_DIR}/Meridian.app.tar.gz"
|
||||
(cd desktop && pnpm tauri signer sign "$TARBALL_ABS")
|
||||
|
||||
- name: Verify code signature
|
||||
run: |
|
||||
APP_DIR="desktop/src-tauri/target/${TARGET}/release/bundle/macos/Codebase Chat.app"
|
||||
APP_DIR="desktop/src-tauri/target/${TARGET}/release/bundle/macos/Meridian.app"
|
||||
codesign --verify --deep --strict --verbose=2 "$APP_DIR"
|
||||
spctl --assess --type execute --verbose=4 "$APP_DIR"
|
||||
desktop/scripts/verify-macos-entitlements.sh "$APP_DIR"
|
||||
|
|
@ -462,7 +462,7 @@ jobs:
|
|||
- name: Upload updater archive to rolling release
|
||||
if: github.ref == format('refs/tags/v{0}', needs.setup.outputs.version)
|
||||
run: |
|
||||
gh release upload codebase-chat-desktop-latest \
|
||||
gh release upload meridian-desktop-latest \
|
||||
"$ARCHIVE_PATH" \
|
||||
"$SIG_PATH" \
|
||||
--clobber
|
||||
|
|
@ -473,7 +473,7 @@ jobs:
|
|||
|
||||
release-linux:
|
||||
name: Release Linux
|
||||
if: github.repository == 'codebase/codebase-chat'
|
||||
if: github.repository == 'r2d2/meridian'
|
||||
runs-on: ubuntu-latest
|
||||
# Digest-pinned like the SHA-pinned actions below; Renovate keeps it fresh.
|
||||
container: ubuntu:24.04@sha256:4fbb8e6a8395de5a7550b33509421a2bafbc0aab6c06ba2cef9ebffbc7092d90
|
||||
|
|
@ -611,20 +611,20 @@ jobs:
|
|||
|
||||
- name: Build sidecars
|
||||
run: |
|
||||
cargo build --release -p codebase-chat-acp -p codebase-chat-agent -p codebase-chat-dev-mcp -p git-credential-nostr -p codebase-chat-cli
|
||||
cargo build --release -p meridian-acp -p meridian-agent -p meridian-dev-mcp -p git-credential-nostr -p meridian-cli
|
||||
./scripts/bundle-sidecars.sh
|
||||
|
||||
- name: Generate release config
|
||||
run: cd desktop && node scripts/build-release-config.mjs
|
||||
env:
|
||||
CODEBASE_CHAT_UPDATER_PUBLIC_KEY: ${{ secrets.CODEBASE_CHAT_UPDATER_PUBLIC_KEY || secrets.SPROUT_UPDATER_PUBLIC_KEY }}
|
||||
CODEBASE_CHAT_UPDATER_ENDPOINT: https://github.com/codebase/codebase-chat/releases/download/codebase-chat-desktop-latest/latest.json
|
||||
MERIDIAN_UPDATER_PUBLIC_KEY: ${{ secrets.MERIDIAN_UPDATER_PUBLIC_KEY || secrets.SPROUT_UPDATER_PUBLIC_KEY }}
|
||||
MERIDIAN_UPDATER_ENDPOINT: https://github.com/r2d2/meridian/releases/download/meridian-desktop-latest/latest.json
|
||||
|
||||
- name: Build Linux Tauri app
|
||||
run: cd desktop && pnpm tauri build --verbose --ci --bundles deb,appimage --config src-tauri/tauri.release.conf.json
|
||||
env:
|
||||
CODEBASE_CHAT_UPDATER_PUBLIC_KEY: ${{ secrets.CODEBASE_CHAT_UPDATER_PUBLIC_KEY || secrets.SPROUT_UPDATER_PUBLIC_KEY }}
|
||||
CODEBASE_CHAT_UPDATER_ENDPOINT: https://github.com/codebase/codebase-chat/releases/download/codebase-chat-desktop-latest/latest.json
|
||||
MERIDIAN_UPDATER_PUBLIC_KEY: ${{ secrets.MERIDIAN_UPDATER_PUBLIC_KEY || secrets.SPROUT_UPDATER_PUBLIC_KEY }}
|
||||
MERIDIAN_UPDATER_ENDPOINT: https://github.com/r2d2/meridian/releases/download/meridian-desktop-latest/latest.json
|
||||
CMAKE_POLICY_VERSION_MINIMUM: "3.5"
|
||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
|
||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
|
||||
|
|
@ -704,7 +704,7 @@ jobs:
|
|||
- name: Upload updater archive to rolling release
|
||||
if: github.ref == format('refs/tags/v{0}', needs.setup.outputs.version)
|
||||
run: |
|
||||
gh release upload codebase-chat-desktop-latest \
|
||||
gh release upload meridian-desktop-latest \
|
||||
"$ARCHIVE_PATH" \
|
||||
"$SIG_PATH" \
|
||||
--clobber
|
||||
|
|
@ -767,21 +767,21 @@ jobs:
|
|||
shell: bash
|
||||
run: cd desktop && node scripts/build-release-config.mjs
|
||||
env:
|
||||
CODEBASE_CHAT_UPDATER_PUBLIC_KEY: ${{ secrets.CODEBASE_CHAT_UPDATER_PUBLIC_KEY || secrets.SPROUT_UPDATER_PUBLIC_KEY }}
|
||||
CODEBASE_CHAT_UPDATER_ENDPOINT: https://github.com/codebase/codebase-chat/releases/download/codebase-chat-desktop-latest/latest.json
|
||||
MERIDIAN_UPDATER_PUBLIC_KEY: ${{ secrets.MERIDIAN_UPDATER_PUBLIC_KEY || secrets.SPROUT_UPDATER_PUBLIC_KEY }}
|
||||
MERIDIAN_UPDATER_ENDPOINT: https://github.com/r2d2/meridian/releases/download/meridian-desktop-latest/latest.json
|
||||
|
||||
- name: Build sidecars
|
||||
shell: bash
|
||||
run: |
|
||||
cargo build --release --target "$TARGET" -p codebase-chat-acp -p codebase-chat-agent -p codebase-chat-dev-mcp -p git-credential-nostr -p codebase-chat-cli
|
||||
cargo build --release --target "$TARGET" -p meridian-acp -p meridian-agent -p meridian-dev-mcp -p git-credential-nostr -p meridian-cli
|
||||
./scripts/bundle-sidecars.sh "$TARGET"
|
||||
|
||||
- name: Build Windows NSIS installer (unsigned)
|
||||
shell: bash
|
||||
run: cd desktop && pnpm tauri build --verbose --target "$TARGET" --bundles nsis --config src-tauri/tauri.release.conf.json
|
||||
env:
|
||||
CODEBASE_CHAT_UPDATER_PUBLIC_KEY: ${{ secrets.CODEBASE_CHAT_UPDATER_PUBLIC_KEY || secrets.SPROUT_UPDATER_PUBLIC_KEY }}
|
||||
CODEBASE_CHAT_UPDATER_ENDPOINT: https://github.com/codebase/codebase-chat/releases/download/codebase-chat-desktop-latest/latest.json
|
||||
MERIDIAN_UPDATER_PUBLIC_KEY: ${{ secrets.MERIDIAN_UPDATER_PUBLIC_KEY || secrets.SPROUT_UPDATER_PUBLIC_KEY }}
|
||||
MERIDIAN_UPDATER_ENDPOINT: https://github.com/r2d2/meridian/releases/download/meridian-desktop-latest/latest.json
|
||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
|
||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
|
||||
CMAKE_POLICY_VERSION_MINIMUM: "3.5"
|
||||
|
|
@ -838,7 +838,7 @@ jobs:
|
|||
if: github.ref == format('refs/tags/v{0}', needs.setup.outputs.version)
|
||||
shell: bash
|
||||
run: |
|
||||
gh release upload codebase-chat-desktop-latest \
|
||||
gh release upload meridian-desktop-latest \
|
||||
"$ARCHIVE_PATH" \
|
||||
"$SIG_PATH" \
|
||||
--clobber
|
||||
|
|
@ -911,7 +911,7 @@ jobs:
|
|||
ARCHIVE_WIN: ${{ needs.release-windows.outputs.archive_name }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
BASE="https://github.com/codebase/codebase-chat/releases/download/codebase-chat-desktop-latest"
|
||||
BASE="https://github.com/r2d2/meridian/releases/download/meridian-desktop-latest"
|
||||
ARCHIVES=()
|
||||
|
||||
add_archive() {
|
||||
|
|
@ -957,7 +957,7 @@ jobs:
|
|||
ARCHIVE_WIN: ${{ needs.release-windows.outputs.archive_name }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
BASE="https://github.com/codebase/codebase-chat/releases/download/codebase-chat-desktop-latest"
|
||||
BASE="https://github.com/r2d2/meridian/releases/download/meridian-desktop-latest"
|
||||
TRIPLES=()
|
||||
|
||||
add_triple() {
|
||||
|
|
@ -979,4 +979,4 @@ jobs:
|
|||
|
||||
- name: Upload latest.json to rolling release
|
||||
run: |
|
||||
gh release upload codebase-chat-desktop-latest latest.json --clobber
|
||||
gh release upload meridian-desktop-latest latest.json --clobber
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ on:
|
|||
pull_request:
|
||||
paths:
|
||||
- ".github/workflows/reply-persistence-benchmark.yml"
|
||||
- "crates/codebase-chat-db/src/event.rs"
|
||||
- "crates/meridian-db/src/event.rs"
|
||||
- "docker-compose.yml"
|
||||
- "scripts/benchmark-reply-path.sh"
|
||||
- "scripts/test-benchmark-reply-path.sh"
|
||||
|
|
|
|||
16
.github/workflows/signed-macos-canary.yml
vendored
16
.github/workflows/signed-macos-canary.yml
vendored
|
|
@ -12,7 +12,7 @@ permissions:
|
|||
jobs:
|
||||
build:
|
||||
name: Build signed macOS canary
|
||||
if: github.repository == 'codebase/codebase-chat'
|
||||
if: github.repository == 'r2d2/meridian'
|
||||
runs-on: macos-latest
|
||||
timeout-minutes: 60
|
||||
permissions:
|
||||
|
|
@ -93,7 +93,7 @@ jobs:
|
|||
|
||||
- name: Build sidecars
|
||||
run: |
|
||||
cargo build --release -p codebase-chat-acp -p codebase-chat-agent -p codebase-chat-dev-mcp -p git-credential-nostr -p codebase-chat-cli
|
||||
cargo build --release -p meridian-acp -p meridian-agent -p meridian-dev-mcp -p git-credential-nostr -p meridian-cli
|
||||
./scripts/bundle-sidecars.sh
|
||||
|
||||
# Mesh rev derived from Cargo.lock (no lockstep edit on dep bump); cache key tracks it.
|
||||
|
|
@ -176,7 +176,7 @@ jobs:
|
|||
codesign-s3-bucket: ${{ secrets.CODESIGN_S3_BUCKET }}
|
||||
unsigned-artifact-path: ${{ steps.unsigned.outputs.dmg }}
|
||||
entitlements-plist-path: ${{ runner.temp }}/entitlements.plist
|
||||
artifact-name: codebase-chat-canary-${{ github.sha }}-${{ github.run_id }}-arm64
|
||||
artifact-name: meridian-canary-${{ github.sha }}-${{ github.run_id }}-arm64
|
||||
|
||||
- name: Verify signed app
|
||||
env:
|
||||
|
|
@ -186,9 +186,9 @@ jobs:
|
|||
EXTRACT_DIR="${RUNNER_TEMP}/signed-app-extract"
|
||||
rm -rf "$EXTRACT_DIR" && mkdir -p "$EXTRACT_DIR"
|
||||
ditto -x -k "$SIGNED_APP_ZIP" "$EXTRACT_DIR"
|
||||
codesign --verify --deep --strict --verbose=2 "$EXTRACT_DIR/Codebase Chat.app"
|
||||
spctl --assess --type execute --verbose=4 "$EXTRACT_DIR/Codebase Chat.app"
|
||||
desktop/scripts/verify-macos-entitlements.sh "$EXTRACT_DIR/Codebase Chat.app"
|
||||
codesign --verify --deep --strict --verbose=2 "$EXTRACT_DIR/Meridian.app"
|
||||
spctl --assess --type execute --verbose=4 "$EXTRACT_DIR/Meridian.app"
|
||||
desktop/scripts/verify-macos-entitlements.sh "$EXTRACT_DIR/Meridian.app"
|
||||
|
||||
- name: Stage signed DMG
|
||||
id: artifact
|
||||
|
|
@ -197,7 +197,7 @@ jobs:
|
|||
VERSION: ${{ steps.version.outputs.version }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
NAME="CodebaseChat_${VERSION}_aarch64-signed.dmg"
|
||||
NAME="Meridian_${VERSION}_aarch64-signed.dmg"
|
||||
cp "$SIGNED_DMG" "$RUNNER_TEMP/$NAME"
|
||||
echo "path=$RUNNER_TEMP/$NAME" >> "$GITHUB_OUTPUT"
|
||||
echo "name=$NAME" >> "$GITHUB_OUTPUT"
|
||||
|
|
@ -205,7 +205,7 @@ jobs:
|
|||
- name: Upload signed canary
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
with:
|
||||
name: codebase-chat-macos-canary-${{ github.sha }}
|
||||
name: meridian-macos-canary-${{ github.sha }}
|
||||
path: ${{ steps.artifact.outputs.path }}
|
||||
if-no-files-found: error
|
||||
retention-days: 7
|
||||
|
|
|
|||
10
.github/workflows/sprig.yml
vendored
10
.github/workflows/sprig.yml
vendored
|
|
@ -1,9 +1,9 @@
|
|||
name: Sprig
|
||||
|
||||
# Builds and publishes Sprig — one deploy-anywhere Linux multicall binary for:
|
||||
# codebase-chat-acp ACP harness that bridges Codebase Chat events to the LLM agent
|
||||
# codebase-chat-agent ACP-compliant agent (spawns MCP, calls LLMs)
|
||||
# codebase-chat-dev-mcp Developer MCP server (multicall: rg, tree, codebase-chat,
|
||||
# meridian-acp ACP harness that bridges Meridian events to the LLM agent
|
||||
# meridian-agent ACP-compliant agent (spawns MCP, calls LLMs)
|
||||
# meridian-dev-mcp Developer MCP server (multicall: rg, tree, meridian,
|
||||
# git-credential-nostr, git-sign-nostr)
|
||||
#
|
||||
# Targets: x86_64-unknown-linux-musl and aarch64-unknown-linux-musl (static
|
||||
|
|
@ -137,7 +137,7 @@ jobs:
|
|||
set -euo pipefail
|
||||
TAG="sprig-latest"
|
||||
TITLE="Sprig (rolling)"
|
||||
NOTES="Rolling Linux build of Sprig (all-in-one codebase-chat-acp + codebase-chat-agent + codebase-chat-dev-mcp), tracking \`main\` (\`${SHA}\`)."
|
||||
NOTES="Rolling Linux build of Sprig (all-in-one meridian-acp + meridian-agent + meridian-dev-mcp), tracking \`main\` (\`${SHA}\`)."
|
||||
|
||||
gh release edit "$TAG" \
|
||||
--prerelease \
|
||||
|
|
@ -180,5 +180,5 @@ jobs:
|
|||
set -euo pipefail
|
||||
gh release create "$TAG" \
|
||||
--title "Sprig v${VERSION}" \
|
||||
--notes "Sprig v${VERSION} — Linux all-in-one builds of codebase-chat-acp + codebase-chat-agent + codebase-chat-dev-mcp." \
|
||||
--notes "Sprig v${VERSION} — Linux all-in-one builds of meridian-acp + meridian-agent + meridian-dev-mcp." \
|
||||
dist/*
|
||||
|
|
|
|||
6
.github/workflows/windows-canary.yml
vendored
6
.github/workflows/windows-canary.yml
vendored
|
|
@ -16,7 +16,7 @@ permissions:
|
|||
jobs:
|
||||
build:
|
||||
name: Build Windows canary
|
||||
if: github.repository == 'codebase/codebase-chat'
|
||||
if: github.repository == 'r2d2/meridian'
|
||||
runs-on: windows-latest
|
||||
timeout-minutes: 60
|
||||
permissions:
|
||||
|
|
@ -122,7 +122,7 @@ jobs:
|
|||
- name: Build sidecars
|
||||
shell: bash
|
||||
run: |
|
||||
cargo build --release --target "$TARGET" -p codebase-chat-acp -p codebase-chat-agent -p codebase-chat-dev-mcp -p git-credential-nostr -p codebase-chat-cli
|
||||
cargo build --release --target "$TARGET" -p meridian-acp -p meridian-agent -p meridian-dev-mcp -p git-credential-nostr -p meridian-cli
|
||||
./scripts/bundle-sidecars.sh "$TARGET"
|
||||
|
||||
- name: Build Windows NSIS installer (unsigned)
|
||||
|
|
@ -147,7 +147,7 @@ jobs:
|
|||
- name: Upload Windows canary installer
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
with:
|
||||
name: codebase-chat-windows-canary-${{ github.sha }}
|
||||
name: meridian-windows-canary-${{ github.sha }}
|
||||
path: ${{ steps.artifact.outputs.exe }}
|
||||
if-no-files-found: error
|
||||
retention-days: 7
|
||||
|
|
|
|||
6
.gitignore
vendored
6
.gitignore
vendored
|
|
@ -52,9 +52,9 @@ node_modules/
|
|||
.sqlx/
|
||||
|
||||
# SQLite database (created by relay in CWD)
|
||||
codebase-chat.db
|
||||
codebase-chat.db-wal
|
||||
codebase-chat.db-shm
|
||||
meridian.db
|
||||
meridian.db-wal
|
||||
meridian.db-shm
|
||||
|
||||
# Docker volumes (if mounted locally)
|
||||
mysql-data/
|
||||
|
|
|
|||
|
|
@ -14,15 +14,15 @@ lives in the root `VISION*.md`; history lives in `CHANGELOG.md`.
|
|||
| --- | --- | --- |
|
||||
| `features/` | Feature specs — five preview features, nine Stoat Chat parity gaps, a payments protocol spec, infrastructure plans, and hosted-service plans. `README.md` is the local contract: the index, the mandated doc shape, and the cross-cutting findings | yes |
|
||||
| `epics/` | Implementation plans that connect feature intent to bead state, exact code surfaces, TDD slices, and current proof gates | yes |
|
||||
| `rebrand/` | `README.md` — the Buzz → Codebase rebrand record: brand definition (palette, symbol, wordmark, starter agents, icons), what landed, what is outstanding | yes |
|
||||
| `rebrand/` | `README.md` — the Buzz → Meridian rebrand record: brand definition (palette, symbol, wordmark, starter agents, icons), what landed, what is outstanding | yes |
|
||||
| `reference-docs/goat/` | Derived Markdown distillations `00`–`06` of the GOAT/EFDI source PDFs — the basis of root `AGENTS.md` § Design Law | `.md` yes, `.pdf` **no** |
|
||||
| `reference-code/` | Third-party checkouts read while writing the parity docs: `buzz-for-desktop`, `buzz-for-web`, `codebase-cli`, `emdash`, `nips`, `stoatchat` | **no** |
|
||||
| `reference-code/` | Third-party checkouts read while writing the parity docs: `buzz-for-desktop`, `buzz-for-web`, `meridian-cli`, `emdash`, `nips`, `stoatchat` | **no** |
|
||||
|
||||
## Local Contracts
|
||||
|
||||
- **`reference-code/` is read-only, and its `AGENTS.md` files are not ours.** The
|
||||
directory is gitignored (`.gitignore:93`); each entry is a full clone with its
|
||||
own `.git`. `codebase-cli/` alone carries ~30 nested `AGENTS.md` plus a
|
||||
own `.git`. `meridian-cli/` alone carries ~30 nested `AGENTS.md` plus a
|
||||
`CLAUDE.md`, and `emdash/` carries more. Step 4 of Read Before Editing walks an
|
||||
agent straight into them. **They are upstream documents describing upstream
|
||||
repos and are never binding here** — the STELLAR chain stops at this file. Edits
|
||||
|
|
|
|||
|
|
@ -26,14 +26,14 @@ this document.
|
|||
|
||||
| Surface | Files | Responsibility |
|
||||
| --- | --- | --- |
|
||||
| Production authentication | `crates/codebase-chat-control-plane/src/identity.rs` | OIDC discovery, PKCE exchange, trusted principal claims |
|
||||
| Ownership lifecycle | `crates/codebase-chat-control-plane/src/http.rs`, `src/model.rs` | identity bind/unbind, relay-authoritative ownership denial |
|
||||
| Repairable projection | `crates/codebase-chat-control-plane/src/store.rs`, `src/http.rs` | `community_id -> host` projection and reconciliation |
|
||||
| Browser page | `crates/codebase-chat-control-plane/src/http.rs` | session bootstrap, CSP, resilient registration UI |
|
||||
| Integration proof | `crates/codebase-chat-control-plane/tests/integration_control_plane.rs` | Postgres + NIP-98-verifying relay stub |
|
||||
| Production authentication | `crates/meridian-control-plane/src/identity.rs` | OIDC discovery, PKCE exchange, trusted principal claims |
|
||||
| Ownership lifecycle | `crates/meridian-control-plane/src/http.rs`, `src/model.rs` | identity bind/unbind, relay-authoritative ownership denial |
|
||||
| Repairable projection | `crates/meridian-control-plane/src/store.rs`, `src/http.rs` | `community_id -> host` projection and reconciliation |
|
||||
| Browser page | `crates/meridian-control-plane/src/http.rs` | session bootstrap, CSP, resilient registration UI |
|
||||
| Integration proof | `crates/meridian-control-plane/tests/integration_control_plane.rs` | Postgres + NIP-98-verifying relay stub |
|
||||
| Browser proof | `desktop/tests/control-plane/communities-page.spec.mjs` | real browser session, signed binding, create/archive/restore |
|
||||
| Desktop parity | `desktop/src/features/communities/`, `desktop/src/features/settings/ui/HostedCommunitiesSettingsCard.tsx` | deployment limit and identity-lifecycle error copy |
|
||||
| Deployment | `deploy/charts/codebase-chat-control-plane/`, `.github/workflows/control-plane.yml` | resource bounds, topology, monitoring, immutable delivery |
|
||||
| Deployment | `deploy/charts/meridian-control-plane/`, `.github/workflows/control-plane.yml` | resource bounds, topology, monitoring, immutable delivery |
|
||||
|
||||
## Implementation Slices
|
||||
|
||||
|
|
@ -43,15 +43,15 @@ this document.
|
|||
|
||||
**Files:**
|
||||
|
||||
- Modify: `crates/codebase-chat-control-plane/src/identity.rs`
|
||||
- Test: `crates/codebase-chat-control-plane/src/identity.rs`
|
||||
- Modify: `crates/meridian-control-plane/src/identity.rs`
|
||||
- Test: `crates/meridian-control-plane/src/identity.rs`
|
||||
|
||||
**Steps:**
|
||||
|
||||
1. Write an async OIDC-stub test whose token response contains a forged
|
||||
`id_token` subject and whose bearer-authenticated UserInfo response contains
|
||||
the real subject; expect the real subject.
|
||||
2. Run `cargo test -p codebase-chat-control-plane identity::tests::oidc_` and
|
||||
2. Run `cargo test -p meridian-control-plane identity::tests::oidc_` and
|
||||
verify the test fails because the forged payload wins.
|
||||
3. Require discovery to advertise UserInfo, check its HTTP status, and derive
|
||||
the principal only from that response. Validate the discovered issuer and
|
||||
|
|
@ -65,17 +65,17 @@ this document.
|
|||
|
||||
**Files:**
|
||||
|
||||
- Modify: `crates/codebase-chat-control-plane/src/model.rs`
|
||||
- Modify: `crates/codebase-chat-control-plane/src/http.rs`
|
||||
- Modify: `crates/meridian-control-plane/src/model.rs`
|
||||
- Modify: `crates/meridian-control-plane/src/http.rs`
|
||||
- Modify: `desktop/src/features/communities/hostedCommunityApi.ts`
|
||||
- Test: `crates/codebase-chat-control-plane/tests/integration_control_plane.rs`
|
||||
- Test: `crates/meridian-control-plane/tests/integration_control_plane.rs`
|
||||
|
||||
**Steps:**
|
||||
|
||||
1. Write integration tests proving delete is rejected for a key with an active
|
||||
community and for the same community after archive.
|
||||
2. Run the focused integration tests with
|
||||
`CODEBASE_CHAT_TEST_DATABASE_URL=postgres://...`; expect FAIL.
|
||||
`MERIDIAN_TEST_DATABASE_URL=postgres://...`; expect FAIL.
|
||||
3. Add `identity_in_use`. Before unbind, resolve the current identity and query
|
||||
authoritative relay ownership; reject when any row remains.
|
||||
4. Add desktop/browser copy that says ownership must be transferred first.
|
||||
|
|
@ -87,9 +87,9 @@ this document.
|
|||
|
||||
**Files:**
|
||||
|
||||
- Modify: `crates/codebase-chat-control-plane/src/store.rs`
|
||||
- Modify: `crates/codebase-chat-control-plane/src/http.rs`
|
||||
- Test: `crates/codebase-chat-control-plane/tests/integration_control_plane.rs`
|
||||
- Modify: `crates/meridian-control-plane/src/store.rs`
|
||||
- Modify: `crates/meridian-control-plane/src/http.rs`
|
||||
- Test: `crates/meridian-control-plane/tests/integration_control_plane.rs`
|
||||
|
||||
**Steps:**
|
||||
|
||||
|
|
@ -110,8 +110,8 @@ this document.
|
|||
|
||||
**Files:**
|
||||
|
||||
- Modify: `crates/codebase-chat-control-plane/src/http.rs`
|
||||
- Test: `crates/codebase-chat-control-plane/tests/integration_control_plane.rs`
|
||||
- Modify: `crates/meridian-control-plane/src/http.rs`
|
||||
- Test: `crates/meridian-control-plane/tests/integration_control_plane.rs`
|
||||
|
||||
**Steps:**
|
||||
|
||||
|
|
@ -155,13 +155,13 @@ this document.
|
|||
|
||||
**Files:**
|
||||
|
||||
- Modify: `crates/codebase-chat-control-plane/src/config.rs`
|
||||
- Modify: `crates/codebase-chat-control-plane/src/http.rs`
|
||||
- Modify: `crates/codebase-chat-control-plane/src/main.rs`
|
||||
- Modify: `deploy/charts/codebase-chat-control-plane/values.yaml`
|
||||
- Modify: `deploy/charts/codebase-chat-control-plane/values.schema.json`
|
||||
- Modify: `deploy/charts/codebase-chat-control-plane/templates/deployment.yaml`
|
||||
- Test: `deploy/charts/codebase-chat-control-plane/tests/render.sh`
|
||||
- Modify: `crates/meridian-control-plane/src/config.rs`
|
||||
- Modify: `crates/meridian-control-plane/src/http.rs`
|
||||
- Modify: `crates/meridian-control-plane/src/main.rs`
|
||||
- Modify: `deploy/charts/meridian-control-plane/values.yaml`
|
||||
- Modify: `deploy/charts/meridian-control-plane/values.schema.json`
|
||||
- Modify: `deploy/charts/meridian-control-plane/templates/deployment.yaml`
|
||||
- Test: `deploy/charts/meridian-control-plane/tests/render.sh`
|
||||
|
||||
**Steps:**
|
||||
|
||||
|
|
@ -190,8 +190,8 @@ this document.
|
|||
|
||||
**Files:**
|
||||
|
||||
- Modify: `crates/codebase-chat-control-plane/src/metrics.rs`
|
||||
- Modify: `deploy/charts/codebase-chat-control-plane/`
|
||||
- Modify: `crates/meridian-control-plane/src/metrics.rs`
|
||||
- Modify: `deploy/charts/meridian-control-plane/`
|
||||
- Modify: `.github/workflows/control-plane.yml`
|
||||
- Modify: `docs/control-plane-deployment.md`
|
||||
|
||||
|
|
@ -258,13 +258,13 @@ or workflow is ever allowed to grant relay ownership.
|
|||
|
||||
```bash
|
||||
. ./bin/activate-hermit
|
||||
CODEBASE_CHAT_TEST_DATABASE_URL=postgres://codebase_chat:codebase_chat_dev@localhost:5432/postgres \
|
||||
cargo test -p codebase-chat-control-plane --all-targets
|
||||
cargo clippy -p codebase-chat-control-plane --all-targets -- -D warnings
|
||||
cargo fmt --check -p codebase-chat-control-plane
|
||||
MERIDIAN_TEST_DATABASE_URL=postgres://meridian:meridian_dev@localhost:5432/postgres \
|
||||
cargo test -p meridian-control-plane --all-targets
|
||||
cargo clippy -p meridian-control-plane --all-targets -- -D warnings
|
||||
cargo fmt --check -p meridian-control-plane
|
||||
pnpm -C desktop check
|
||||
pnpm -C desktop exec playwright test --config tests/control-plane/playwright.config.mjs
|
||||
bash deploy/charts/codebase-chat-control-plane/tests/render.sh
|
||||
bash deploy/charts/meridian-control-plane/tests/render.sh
|
||||
```
|
||||
|
||||
Live gates remain the provisioned-host `101 Switching Protocols` and unknown-host
|
||||
|
|
@ -274,8 +274,8 @@ Live gates remain the provisioned-host `101 Switching Protocols` and unknown-hos
|
|||
|
||||
- Initial council audit and red-test baseline: 2026-08-01.
|
||||
- Relay quota concurrency was re-checked and is already safe via the per-owner
|
||||
PostgreSQL advisory lock in `codebase-chat-db/src/lib.rs`.
|
||||
- `cargo test -p codebase-chat-control-plane --all-targets --no-fail-fast`:
|
||||
PostgreSQL advisory lock in `meridian-db/src/lib.rs`.
|
||||
- `cargo test -p meridian-control-plane --all-targets --no-fail-fast`:
|
||||
51 unit and 27 PostgreSQL integration tests passed. The added lifecycle tests
|
||||
prove a one-connection pool cannot self-starve and cover successful transfer,
|
||||
new-owner management, and old-owner disconnect.
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ Helm parity fixtures.
|
|||
|
||||
- `.settings/features/feature-portable-deployment-profiles.md`
|
||||
- `deploy/compose/README.md`
|
||||
- `deploy/charts/codebase-chat/README.md`
|
||||
- `deploy/charts/meridian/README.md`
|
||||
- `docs/git-on-object-storage.md`
|
||||
- `docs/runbooks/relay-backup-restore.md`
|
||||
|
||||
|
|
@ -56,9 +56,9 @@ order below, determines executable work.
|
|||
| Deployment parity | `deploy/profiles/README.md` (new), `scripts/test-deployment-profile-parity.sh` (new) | Shared ports, state, secret, health, migration, and support-tier assertions |
|
||||
| Dokploy distribution | `deploy/dokploy/template/` (new) | Upstream-compatible Compose, `template.toml`, metadata fixture, import smoke |
|
||||
| HA reference | `deploy/dokploy/stack.yml` (new) | Prebuilt relay replicas with external state and Swarm/Traefik labels |
|
||||
| Object storage | `crates/codebase-chat-media/`, `crates/codebase-chat-relay/src/api/git/`, `docs/git-on-object-storage.md` | S3 configuration and startup A3 CAS admission |
|
||||
| Object storage | `crates/meridian-media/`, `crates/meridian-relay/src/api/git/`, `docs/git-on-object-storage.md` | S3 configuration and startup A3 CAS admission |
|
||||
| Recovery | `scripts/verify-backup-restore.sh`, `docs/runbooks/relay-backup-restore.md` | Consistency set, isolated restore, identity/object graph/ACL proof |
|
||||
| Relay health/metrics | `crates/codebase-chat-relay/src/router.rs`, `src/main.rs`, chart Prometheus resources | `/_liveness`, `/_readiness`, `/metrics`, subscriber fencing |
|
||||
| Relay health/metrics | `crates/meridian-relay/src/router.rs`, `src/main.rs`, chart Prometheus resources | `/_liveness`, `/_readiness`, `/metrics`, subscriber fencing |
|
||||
| Cloudflare edge | `deploy/cloudflare/` (new) | R2 example, Tunnel/LB origin contract, optional Worker/Container experiment |
|
||||
| CI | `.github/workflows/ci.yml`, `.github/workflows/docker.yml` | Static adapter validation and disposable live smoke artifacts |
|
||||
|
||||
|
|
@ -212,7 +212,7 @@ docker compose -f deploy/dokploy/compose.yml config
|
|||
bash scripts/test-dokploy-contract.sh
|
||||
bash scripts/test-deployment-profile-parity.sh
|
||||
bash scripts/test-verify-backup-restore.sh
|
||||
helm unittest deploy/charts/codebase-chat
|
||||
helm unittest deploy/charts/meridian
|
||||
just ci
|
||||
```
|
||||
|
||||
|
|
@ -224,10 +224,10 @@ readiness, upgrade, failure, and restore probes named by their support profile.
|
|||
- Planning inventory completed 2026-08-02 against the current Compose, Helm,
|
||||
image, Git/CAS, and recovery contracts.
|
||||
- Dokploy currently documents Compose, Stack/Swarm, clusters, remote servers,
|
||||
automatic deployments, domains, and upstream templates. No Codebase Chat
|
||||
automatic deployments, domains, and upstream templates. No Meridian
|
||||
adapter or live proof exists in this repo.
|
||||
- Cloudflare currently documents R2 S3 compatibility, strong consistency, and
|
||||
conditional operations. The Codebase Chat startup A3 probe has not yet
|
||||
conditional operations. The Meridian startup A3 probe has not yet
|
||||
admitted an R2 deployment.
|
||||
- No implementation or live support evidence is claimed by this plan.
|
||||
|
||||
|
|
@ -244,4 +244,4 @@ readiness, upgrade, failure, and restore probes named by their support profile.
|
|||
- Cloudflare trusted client-IP capture is blocked until direct-origin bypass is
|
||||
prevented and re-probed live.
|
||||
- Upstream Dokploy publication is blocked on a disposable template deployment
|
||||
using an immutable Codebase Chat image.
|
||||
using an immutable Meridian image.
|
||||
|
|
|
|||
|
|
@ -48,16 +48,16 @@ any non-Redis runtime mode or transport claim is introduced.
|
|||
## Proof gates
|
||||
|
||||
```bash
|
||||
cargo test -p codebase-chat-pubsub --lib
|
||||
cargo clippy -p codebase-chat-pubsub --all-targets -- -D warnings
|
||||
REDIS_URL=redis://127.0.0.1:6390 cargo test -p codebase-chat-pubsub \
|
||||
cargo test -p meridian-pubsub --lib
|
||||
cargo clippy -p meridian-pubsub --all-targets -- -D warnings
|
||||
REDIS_URL=redis://127.0.0.1:6390 cargo test -p meridian-pubsub \
|
||||
dedicated_subscriber_faults_fail_health_while_pool_stays_ready_and_recover \
|
||||
-- --ignored --nocapture
|
||||
just subscriber-fault-matrix
|
||||
cargo test -p codebase-chat-relay \
|
||||
cargo test -p meridian-relay \
|
||||
subscriber_outage_fences_registration_and_reopens_after_recovery --lib
|
||||
cargo check -p codebase-chat-relay
|
||||
cargo test -p codebase-chat-db migration::tests
|
||||
cargo check -p meridian-relay
|
||||
cargo test -p meridian-db migration::tests
|
||||
REPLY_BENCH_ALLOW_DATABASE_MUTATION=1 scripts/benchmark-reply-path.sh
|
||||
just ci
|
||||
```
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Features
|
||||
|
||||
Feature specs for Codebase Chat. Each doc is a working contract for one area:
|
||||
Feature specs for Meridian. Each doc is a working contract for one area:
|
||||
what it is, what it currently is *actually* (grounded in file paths, not
|
||||
intent), where the gaps are, and the bite-sized tasks that close them.
|
||||
|
||||
|
|
@ -52,7 +52,7 @@ preview features; most have no flag yet because they have no code yet.
|
|||
|
||||
- [feature-parity-index.md](./feature-parity-index.md) — **read first.** The
|
||||
matrix, the suggested order, and the table of reference features *examined and
|
||||
excluded* because Codebase Chat already has an equivalent.
|
||||
excluded* because Meridian already has an equivalent.
|
||||
- [feature-granular-permissions.md](./feature-granular-permissions.md) —
|
||||
**high** · authorization is a three-value string role; kind 39003 orphaned.
|
||||
Unblocks four specs below.
|
||||
|
|
|
|||
|
|
@ -12,15 +12,15 @@
|
|||
|
||||
# Feature: Agent Distribution
|
||||
|
||||
Codebase Chat has a deeper agent story than the reference has a bot story — ACP
|
||||
Meridian has a deeper agent story than the reference has a bot story — ACP
|
||||
harness, personas, teams, engram memory, owner-reviewed drafts, turn metrics.
|
||||
On capability, this is not a gap; it is a lead.
|
||||
|
||||
On **distribution** it is a gap, and a sharp one. Every agent in Codebase Chat
|
||||
On **distribution** it is a gap, and a sharp one. Every agent in Meridian
|
||||
is defined by one workspace owner for one workspace. `KIND_MANAGED_AGENT`
|
||||
(30177) is addressed by `(owner_pubkey, kind, agent_pubkey)` and its doc comment
|
||||
says so plainly: *"published by the workspace owner"*
|
||||
(`crates/codebase-chat-core/src/kind.rs:252-259`). There is no way for someone
|
||||
(`crates/meridian-core/src/kind.rs:252-259`). There is no way for someone
|
||||
to build an agent and let another community use it. Build a good code-review
|
||||
agent for your team and a neighbouring team must rebuild it from scratch.
|
||||
|
||||
|
|
@ -41,7 +41,7 @@ The reference's model cannot be copied here. Its `Bot` carries a `token`
|
|||
(`crates/core/models/src/v0/bots.rs:15`) and inviting a bot to your server
|
||||
grants *the publisher's* running process access to your messages. That is a
|
||||
reasonable trade for a hosted consumer platform and the wrong one for a tool
|
||||
whose channels contain source code. A Codebase Chat community must never
|
||||
whose channels contain source code. A Meridian community must never
|
||||
execute, or route its content through, infrastructure controlled by a stranger
|
||||
because someone clicked Install.
|
||||
|
||||
|
|
@ -89,9 +89,9 @@ published it.
|
|||
|
||||
## Current State
|
||||
|
||||
**Codebase Chat — agents are workspace-local by construction.**
|
||||
**Meridian — agents are workspace-local by construction.**
|
||||
|
||||
`crates/codebase-chat-core/src/kind.rs:252-259`:
|
||||
`crates/meridian-core/src/kind.rs:252-259`:
|
||||
|
||||
```rust
|
||||
/// NIP-AP: Managed Agent (parameterized replaceable, owner-authored).
|
||||
|
|
@ -116,20 +116,20 @@ reference, `:87`), `KIND_PERSONA` (30175), `KIND_TEAM` (30176, "user-facing
|
|||
grouping of personas", `:245-250`), `KIND_AGENT_ENGRAM` (30174, encrypted
|
||||
memory).
|
||||
|
||||
Crates: `codebase-chat-acp`, `codebase-chat-agent`, `codebase-chat-persona`,
|
||||
`codebase-chat-dev-mcp`, `sprig`. Desktop: `features/agents/`,
|
||||
Crates: `meridian-acp`, `meridian-agent`, `meridian-persona`,
|
||||
`meridian-dev-mcp`, `sprig`. Desktop: `features/agents/`,
|
||||
`features/agent-memory/`.
|
||||
|
||||
No discovery concept exists at any layer:
|
||||
|
||||
```bash
|
||||
grep -rn "discoverable\|marketplace\|public_agent\|publicAgent\|directory" \
|
||||
crates/codebase-chat-core/src crates/codebase-chat-relay/src/handlers
|
||||
crates/meridian-core/src crates/meridian-relay/src/handlers
|
||||
```
|
||||
|
||||
One hit, an unrelated comment in `moderation_notices.rs:149`.
|
||||
|
||||
| Capability | Codebase Chat | Reference |
|
||||
| Capability | Meridian | Reference |
|
||||
| --- | --- | --- |
|
||||
| Owner-defined agent | ✅ 30177 | ✅ `Bot` |
|
||||
| Persona / prompt config | ✅ 30175, 30176 | ❌ |
|
||||
|
|
@ -140,7 +140,7 @@ One hit, an unrelated comment in `moderation_notices.rs:149`.
|
|||
| **Third-party discovery** | ❌ | ✅ `fetch_public_bot` |
|
||||
| **Install into a community** | ❌ | ✅ `invite_bot` |
|
||||
|
||||
Codebase Chat leads on five of eight rows and has none of the last three.
|
||||
Meridian leads on five of eight rows and has none of the last three.
|
||||
|
||||
**Reference — a token and a public flag.**
|
||||
|
||||
|
|
@ -166,7 +166,7 @@ minimal.
|
|||
| --- | --- | --- | --- |
|
||||
| A1 | An agent definition cannot leave the workspace that created it. Every community rebuilds the same agents. | 30177 addressed by owner pubkey, `kind.rs:252-259` | medium |
|
||||
| A2 | No discovery primitive — no way to fetch an agent definition you did not author. | `grep` for discovery terms returns one unrelated comment | medium |
|
||||
| A3 | No install flow, so no capability gates it and no audit records it. | absence of any install path; `codebase-chat-audit` has no agent-install entry | medium |
|
||||
| A3 | No install flow, so no capability gates it and no audit records it. | absence of any install path; `meridian-audit` has no agent-install entry | medium |
|
||||
| A4 | Personas and teams (30175/30176) are equally workspace-local, so even the reusable, secret-free half of an agent cannot be shared. | `kind.rs:245-250` — "published by the workspace owner" | low |
|
||||
| A5 | **Prospective:** a definition format that permits a URL, endpoint, or token would let a publisher route an installer's content off-box. The rejected model must be excluded by the schema, not by convention. | design risk of A1's fix | high (if built without Phase 1's exclusion list) |
|
||||
| A6 | No definition versioning, so an accepted update has no identity to compare against. | 30177 is replaceable — a new publish silently supersedes | low |
|
||||
|
|
@ -199,7 +199,7 @@ second one that will drift.
|
|||
**Task 1.2: Failing test for the exclusion list**
|
||||
|
||||
Files:
|
||||
- Create: `crates/codebase-chat-core/src/agent_definition.rs`
|
||||
- Create: `crates/meridian-core/src/agent_definition.rs`
|
||||
|
||||
```rust
|
||||
#[test]
|
||||
|
|
@ -222,7 +222,7 @@ fn unknown_fields_are_rejected_not_ignored() {
|
|||
}
|
||||
```
|
||||
|
||||
Run `cargo test -p codebase-chat-core agent_definition` — expected FAIL.
|
||||
Run `cargo test -p meridian-core agent_definition` — expected FAIL.
|
||||
Implement, re-run, expect PASS.
|
||||
|
||||
The third test is the one that holds over time. A pure deny-list is bypassed by
|
||||
|
|
@ -231,7 +231,7 @@ the next field anyone adds; parse strictly and reject unknown fields.
|
|||
**Task 1.3: Allocate the kind**
|
||||
|
||||
Files:
|
||||
- Modify: `crates/codebase-chat-core/src/kind.rs`
|
||||
- Modify: `crates/meridian-core/src/kind.rs`
|
||||
|
||||
Addressable, author = publisher, `d` = stable definition id. Distinct from
|
||||
30177: 30177 is *my agent, running here*; this is *a recipe anyone may
|
||||
|
|
@ -246,7 +246,7 @@ and [`feature-user-blocking.md`](./feature-user-blocking.md)).
|
|||
**Task 2.1: Ingest validation**
|
||||
|
||||
Files:
|
||||
- Modify: `crates/codebase-chat-relay/src/handlers/ingest.rs`
|
||||
- Modify: `crates/meridian-relay/src/handlers/ingest.rs`
|
||||
|
||||
Apply Task 1.2's parser. A definition that fails is rejected, not stored — a
|
||||
stored-but-invalid definition is one client's lenient parser away from being
|
||||
|
|
@ -255,13 +255,13 @@ honoured.
|
|||
**Task 2.2: CLI first**
|
||||
|
||||
Files:
|
||||
- Modify: `crates/codebase-chat-cli/src/commands/agents.rs`
|
||||
- Modify: `crates/codebase-chat-cli/src/lib.rs`
|
||||
- Modify: `crates/meridian-cli/src/commands/agents.rs`
|
||||
- Modify: `crates/meridian-cli/src/lib.rs`
|
||||
|
||||
```
|
||||
codebase-chat agents publish --agent <pubkey> --id <slug>
|
||||
codebase-chat agents fetch-definition --author <hex> --id <slug>
|
||||
codebase-chat agents install --author <hex> --id <slug> [--name "..."]
|
||||
meridian agents publish --agent <pubkey> --id <slug>
|
||||
meridian agents fetch-definition --author <hex> --id <slug>
|
||||
meridian agents install --author <hex> --id <slug> [--name "..."]
|
||||
```
|
||||
|
||||
`install` generates a **fresh keypair**, writes a local 30177 owned by the
|
||||
|
|
@ -272,8 +272,8 @@ Phase 1.
|
|||
**Task 2.3: Capability gate and audit**
|
||||
|
||||
Files:
|
||||
- Modify: `crates/codebase-chat-relay/src/handlers/moderation_authz.rs`
|
||||
- Modify: `crates/codebase-chat-audit/src/lib.rs`
|
||||
- Modify: `crates/meridian-relay/src/handlers/moderation_authz.rs`
|
||||
- Modify: `crates/meridian-audit/src/lib.rs`
|
||||
|
||||
`agent:install`, following the reference's per-scope split
|
||||
(`invite.rs:44,56`). Audit records author, definition id, version, and installer.
|
||||
|
|
@ -281,7 +281,7 @@ Files:
|
|||
**Task 2.4: Personas and teams (closes A4)**
|
||||
|
||||
Files:
|
||||
- Modify: `crates/codebase-chat-core/src/kind.rs` (doc comments)
|
||||
- Modify: `crates/meridian-core/src/kind.rs` (doc comments)
|
||||
|
||||
30175/30176 are already secret-free projections. Allow them to be published and
|
||||
installed by the same path; no new mechanism.
|
||||
|
|
@ -337,8 +337,8 @@ why, so a later audit does not "correct" it.
|
|||
## Verification
|
||||
|
||||
```bash
|
||||
cargo test -p codebase-chat-core agent_definition
|
||||
cargo test -p codebase-chat-relay agent_definition
|
||||
cargo test -p meridian-core agent_definition
|
||||
cargo test -p meridian-relay agent_definition
|
||||
just test
|
||||
just desktop-test
|
||||
just desktop-e2e-smoke
|
||||
|
|
@ -348,14 +348,14 @@ just ci
|
|||
Confirm the parser rejects unknown fields rather than ignoring them:
|
||||
|
||||
```bash
|
||||
cargo test -p codebase-chat-core unknown_fields_are_rejected_not_ignored
|
||||
cargo test -p meridian-core unknown_fields_are_rejected_not_ignored
|
||||
```
|
||||
|
||||
Confirm no secret can cross a community boundary — this is the invariant the
|
||||
whole feature rests on:
|
||||
|
||||
```bash
|
||||
grep -rn "token\|secret_key\|auth_tag\|env" crates/codebase-chat-core/src/agent_definition.rs
|
||||
grep -rn "token\|secret_key\|auth_tag\|env" crates/meridian-core/src/agent_definition.rs
|
||||
```
|
||||
|
||||
Hits outside the rejection list mean a secret-carrying field was added to the
|
||||
|
|
@ -364,5 +364,5 @@ publishable schema.
|
|||
Confirm install mints a new identity:
|
||||
|
||||
```bash
|
||||
cargo test -p codebase-chat-cli agents_install_generates_fresh_keypair
|
||||
cargo test -p meridian-cli agents_install_generates_fresh_keypair
|
||||
```
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
A per-channel cooldown that a moderator sets on a busy channel: one message per
|
||||
N seconds per member, with a capability to bypass it.
|
||||
|
||||
Codebase Chat has rate limiting, and it is not this. The existing limiter is an
|
||||
Meridian has rate limiting, and it is not this. The existing limiter is an
|
||||
**operator-configured anti-abuse control** — fixed windows, set by environment
|
||||
variable, scoped to a principal *class*. Slowmode is a **moderator-configured
|
||||
conversation-pacing tool** — set per channel, in the product, by the person
|
||||
|
|
@ -35,10 +35,10 @@ with a TTL equal to the interval. Presence of the key means "still cooling
|
|||
down"; its TTL is the remaining seconds. This costs one `SET NX EX` on the
|
||||
success path and needs no scheduled cleanup.
|
||||
|
||||
**Rejected: reusing `LimitType` in `codebase-chat-auth`.** That enum is keyed by
|
||||
**Rejected: reusing `LimitType` in `meridian-auth`.** That enum is keyed by
|
||||
principal class (`human`, `agent-standard`, `agent-elevated`, `agent-platform`)
|
||||
and configured from `CODEBASE_CHAT_RATE_LIMIT_*` env vars
|
||||
(`crates/codebase-chat-relay/src/config.rs:305-329`). Slowmode is keyed by
|
||||
and configured from `MERIDIAN_RATE_LIMIT_*` env vars
|
||||
(`crates/meridian-relay/src/config.rs:305-329`). Slowmode is keyed by
|
||||
channel and configured by a moderator at runtime. Threading a runtime, per-channel
|
||||
value through an operator-configured enum would corrupt both.
|
||||
|
||||
|
|
@ -47,7 +47,7 @@ but the relay must be the authority — a client that does not implement slowmod
|
|||
would otherwise bypass it entirely.
|
||||
|
||||
**Deliberate asymmetry: agents are not exempt.** The reference has no notion of
|
||||
an agent principal. Codebase Chat does, and the tempting shortcut is to exempt
|
||||
an agent principal. Meridian does, and the tempting shortcut is to exempt
|
||||
them since they are already rate-limited by class. Do not — an agent posting
|
||||
into a slowmoded channel is exactly the flood the moderator is trying to stop.
|
||||
Exemption is a capability grant, not a principal-class property.
|
||||
|
|
@ -68,21 +68,21 @@ Exemption is a capability grant, not a principal-class property.
|
|||
- **No slowmode on DMs.** It is a moderation tool and DMs have no moderator.
|
||||
- **No retroactive enforcement.** Raising the interval does not extend an
|
||||
in-flight cooldown.
|
||||
- **No replacement of the existing limiter.** The `CODEBASE_CHAT_RATE_LIMIT_*`
|
||||
- **No replacement of the existing limiter.** The `MERIDIAN_RATE_LIMIT_*`
|
||||
controls stay exactly as they are, and slowmode is checked in addition.
|
||||
- **No auto-slowmode.** Automatic engagement under load is a plausible follow-up
|
||||
and is out of scope until manual slowmode has shipped and been used.
|
||||
|
||||
## Current State
|
||||
|
||||
**Codebase Chat — no slowmode at any layer.**
|
||||
**Meridian — no slowmode at any layer.**
|
||||
|
||||
```bash
|
||||
grep -ril "slowmode" crates desktop/src mobile/lib web/src # → no output
|
||||
```
|
||||
|
||||
What exists instead: `crates/codebase-chat-relay/src/admission.rs:17-26`,
|
||||
`check_principal`, delegating to `codebase_chat_auth::RateLimiter` with a
|
||||
What exists instead: `crates/meridian-relay/src/admission.rs:17-26`,
|
||||
`check_principal`, delegating to `meridian_auth::RateLimiter` with a
|
||||
`LimitType` and a window. The in-file comment at `:7` records the shape
|
||||
candidly — "is still a fixed-window limiter, so a Redis-backed token bucket
|
||||
would be a [better fit]".
|
||||
|
|
@ -134,7 +134,7 @@ decision in
|
|||
| --- | --- | --- | --- |
|
||||
| S1 | No per-channel cooldown exists anywhere in the stack. | `grep -ril slowmode` over `crates desktop/src mobile/lib web/src` returns nothing | medium |
|
||||
| S2 | Moderators have no pacing tool between "allow" and "remove the member". A flooding-but-not-abusive member can only be muted or kicked. | `moderation_authz.rs` `ModerationAction` variants | medium |
|
||||
| S3 | The only rate control is operator-scoped, so per-community tuning requires a relay redeploy. | `config.rs:305-329`, all `CODEBASE_CHAT_RATE_LIMIT_*` env-sourced | medium |
|
||||
| S3 | The only rate control is operator-scoped, so per-community tuning requires a relay redeploy. | `config.rs:305-329`, all `MERIDIAN_RATE_LIMIT_*` env-sourced | medium |
|
||||
| S4 | Rate-limit rejections are not surfaced as a countdown; the client learns by failing. | `resetRateLimitGate()` is a gate, not a timer | low |
|
||||
| S5 | Bypass has nowhere to live — there is no capability model to hang it on. | blocked on P1/P2 in `feature-granular-permissions.md` | low (blocking, not severe) |
|
||||
|
||||
|
|
@ -145,8 +145,8 @@ decision in
|
|||
**Task 1.1: Failing test for the cooldown decision**
|
||||
|
||||
Files:
|
||||
- Create: `crates/codebase-chat-relay/src/handlers/slowmode.rs`
|
||||
- Modify: `crates/codebase-chat-relay/src/handlers/mod.rs`
|
||||
- Create: `crates/meridian-relay/src/handlers/slowmode.rs`
|
||||
- Modify: `crates/meridian-relay/src/handlers/mod.rs`
|
||||
|
||||
Keep the pure decision separate from the Dragonfly round trip so it is testable
|
||||
without infrastructure:
|
||||
|
|
@ -168,14 +168,14 @@ fn bypass_wins_over_active_cooldown() {
|
|||
}
|
||||
```
|
||||
|
||||
Run `cargo test -p codebase-chat-relay slowmode` — expected FAIL. Implement,
|
||||
Run `cargo test -p meridian-relay slowmode` — expected FAIL. Implement,
|
||||
re-run, expect PASS.
|
||||
|
||||
**Task 1.2: Interval on channel metadata**
|
||||
|
||||
Files:
|
||||
- Modify: `crates/codebase-chat-relay/src/handlers/relay_admin.rs`
|
||||
- Modify: `crates/codebase-chat-core/src/kind.rs` (doc comment on 39000 only)
|
||||
- Modify: `crates/meridian-relay/src/handlers/relay_admin.rs`
|
||||
- Modify: `crates/meridian-core/src/kind.rs` (doc comment on 39000 only)
|
||||
|
||||
A `slowmode` tag on kind 39000, seconds as a decimal string. Validate
|
||||
`0..=21600` at ingest and reject out-of-range rather than clamping — a silently
|
||||
|
|
@ -184,7 +184,7 @@ clamped 86400 is a moderator who thinks they set a day and got six hours.
|
|||
**Task 1.3: Enforce at ingest**
|
||||
|
||||
Files:
|
||||
- Modify: `crates/codebase-chat-relay/src/handlers/ingest.rs`
|
||||
- Modify: `crates/meridian-relay/src/handlers/ingest.rs`
|
||||
|
||||
Check *after* signature verification and *after* the existing
|
||||
`check_principal` admission call — slowmode is the narrower gate and should not
|
||||
|
|
@ -196,7 +196,7 @@ oversight.
|
|||
**Task 1.4: Integration test**
|
||||
|
||||
Files:
|
||||
- Create: `crates/codebase-chat-test-client/tests/e2e_slowmode.rs`
|
||||
- Create: `crates/meridian-test-client/tests/e2e_slowmode.rs`
|
||||
|
||||
Needs Postgres + Dragonfly, so `just test`, not `just test-unit`. Publish two
|
||||
messages inside the window, assert the second is rejected with remaining
|
||||
|
|
@ -207,10 +207,10 @@ seconds; assert a bypass holder is unaffected; assert kind 7 passes.
|
|||
**Task 2.1: CLI first**
|
||||
|
||||
Files:
|
||||
- Modify: `crates/codebase-chat-cli/src/commands/channels.rs`
|
||||
- Modify: `crates/codebase-chat-cli/src/lib.rs`
|
||||
- Modify: `crates/meridian-cli/src/commands/channels.rs`
|
||||
- Modify: `crates/meridian-cli/src/lib.rs`
|
||||
|
||||
`codebase-chat channels set-slowmode --channel <uuid> --seconds 30`. Per the
|
||||
`meridian channels set-slowmode --channel <uuid> --seconds 30`. Per the
|
||||
root guide, the agent surface lands before the UI and becomes the reference
|
||||
behavior.
|
||||
|
||||
|
|
@ -290,7 +290,7 @@ bug (see the cross-cutting findings in [`README.md`](./README.md)).
|
|||
## Verification
|
||||
|
||||
```bash
|
||||
cargo test -p codebase-chat-relay slowmode
|
||||
cargo test -p meridian-relay slowmode
|
||||
just test # integration; needs Postgres + Dragonfly
|
||||
just desktop-test
|
||||
just desktop-e2e-smoke
|
||||
|
|
@ -302,7 +302,7 @@ Confirm slowmode is distinct from the operator limiter — these must not
|
|||
converge on one code path:
|
||||
|
||||
```bash
|
||||
grep -rn "LimitType\|check_principal" crates/codebase-chat-relay/src/handlers/slowmode.rs
|
||||
grep -rn "LimitType\|check_principal" crates/meridian-relay/src/handlers/slowmode.rs
|
||||
```
|
||||
|
||||
Any output means Task 1.1's separation was not maintained.
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ near-duplicate").
|
|||
## Decision
|
||||
|
||||
**Select on one test: does the capability change meaning when the work becomes
|
||||
shared?** Codebase Chat is making the Excel→Google-Sheets transition — the
|
||||
shared?** Meridian is making the Excel→Google-Sheets transition — the
|
||||
capability existed in the local artifact; what changes is that it becomes a
|
||||
persistent, member-scoped, discoverable property of a workspace other people
|
||||
also inhabit.
|
||||
|
|
@ -43,7 +43,7 @@ That test sorts the nine cleanly:
|
|||
|
||||
| Rejected | Reason |
|
||||
| --- | --- |
|
||||
| Hooks (as a new mechanism) | `codebase-chat-workflow` already occupies this space — YAML automations with approval gates. Root `CLAUDE.md` § Design Law: *"Add attributes, not mechanisms… Rule- or formula-based policy DSLs are explicitly rejected."* A second automation mechanism is the exact failure that law prevents. If workflows are less discoverable than hooks, that is a surfacing bug — workflows are preview-gated today. |
|
||||
| Hooks (as a new mechanism) | `meridian-workflow` already occupies this space — YAML automations with approval gates. Root `CLAUDE.md` § Design Law: *"Add attributes, not mechanisms… Rule- or formula-based policy DSLs are explicitly rejected."* A second automation mechanism is the exact failure that law prevents. If workflows are less discoverable than hooks, that is a surfacing bug — workflows are preview-gated today. |
|
||||
| Pets, Appshots | Reference-product whimsy with no group semantics. |
|
||||
| Computer use of arbitrary desktop apps | Controlling Excel and Chrome on the member's machine is a different product with a different threat model. **Tool rules (item 9) is the part we want** and it is scoped to agent tools we already run, not to the member's desktop. |
|
||||
| Generic "General" catch-all section | Our sections are already specific; a catch-all is where settings go to become unfindable. Search (item 1) solves the discovery problem a General tab pretends to. |
|
||||
|
|
@ -98,8 +98,8 @@ verifiable as presence rows.
|
|||
| 4 | MCP servers | `agents/ui/McpServersSection.tsx`, rendered only at `AgentConfigPanel.tsx:426` | **per-agent** | n/a |
|
||||
| 5 | Identity & Git readiness | `settings/ui/IdentityGitSettingsCard.tsx`; typed probe in `src-tauri/src/commands/identity_git.rs`; recovery gates in `app/App.tsx` | **per profile on this device**, read-only | n/a |
|
||||
| 6 | Plan / billing | absent | — | — |
|
||||
| 7 | Tool rules | absent as a member-visible grant; harness/MCP wiring in `crates/codebase-chat-acp/` | **per-agent config** | — |
|
||||
| 8 | Extension distribution | `KIND_MANAGED_AGENT` (30177), `crates/codebase-chat-core/src/kind.rs:252-259` | **one workspace owner, one workspace** | — |
|
||||
| 7 | Tool rules | absent as a member-visible grant; harness/MCP wiring in `crates/meridian-acp/` | **per-agent config** | — |
|
||||
| 8 | Extension distribution | `KIND_MANAGED_AGENT` (30177), `crates/meridian-core/src/kind.rs:252-259` | **one workspace owner, one workspace** | — |
|
||||
| 9 | Design preview | absent; only `opener:default` in `src-tauri/capabilities/default.json:19` | — | — |
|
||||
|
||||
Two facts that shape the plan:
|
||||
|
|
@ -115,7 +115,7 @@ Two facts that shape the plan:
|
|||
|
||||
| # | Gap | Evidence | Severity |
|
||||
| --- | --- | --- | --- |
|
||||
| G1 | Agent tool authorization is not enumerable. There is no member-visible answer to "which tools may this agent run in this community", and no dated record of who granted it. | no grant rows for tools anywhere under `crates/codebase-chat-core/src/kind.rs` | **high** |
|
||||
| G1 | Agent tool authorization is not enumerable. There is no member-visible answer to "which tools may this agent run in this community", and no dated record of who granted it. | no grant rows for tools anywhere under `crates/meridian-core/src/kind.rs` | **high** |
|
||||
| G2 | **Resolved.** Audio input selection is available before a huddle, reacts in the same window, and survives restart per profile. A disconnected saved device falls back once to the system default; permission failures are not retried. | `VoiceSettingsCard.tsx`; `useAudioInputPreference.ts`; `acquireMicrophoneStream.ts`; focused unit and Playwright coverage | resolved |
|
||||
| G3 | **Resolved.** Lost, locked, and reset-failed identities are intercepted by distinct fail-closed recovery screens before Settings or publish actions mount. Healthy Settings now reports event signing, Git >=2.46 compatibility, NIP-98 Project authentication, NIP-GS tool installation, and global Git author metadata without reading an nsec. | `app/App.tsx`; `commands/identity_git.rs`; `IdentityGitSettingsCard.tsx`; `identity-lost.spec.ts`; `identity-git-settings.spec.ts` | resolved |
|
||||
| G4 | No monetization surface. Nothing in-client states a plan, a limit, or a remaining balance. | absent from `SettingsPanels.tsx` section union | medium |
|
||||
|
|
@ -235,7 +235,7 @@ surfaces existing ones. Criteria that bind the later phases specifically:
|
|||
- **#1/#2 Protocol complete and written down** — Phases 2–4 each introduce
|
||||
kinds (entitlement, tool grant, extension listing, preview target). Each needs
|
||||
a `docs/nips/` document and a reader before merge.
|
||||
- **#6 Agent surface** — tool rules must be readable from `codebase-chat-cli`;
|
||||
- **#6 Agent surface** — tool rules must be readable from `meridian-cli`;
|
||||
an agent that cannot enumerate its own permitted tools cannot explain a
|
||||
denial.
|
||||
- **#7 Failure paths** — Phase 2's limit-reached and Phase 3's denial are the
|
||||
|
|
@ -254,7 +254,7 @@ cd desktop && pnpm exec playwright test tests/e2e/voice-settings.spec.ts --proje
|
|||
rg -n "useAudioInputPreference|acquireMicrophoneStream" desktop/src
|
||||
grep -rn "McpServersSection" desktop/src | grep -v "ui/McpServersSection.tsx:"
|
||||
sed -n '307,318p' desktop/src-tauri/src/app_state.rs
|
||||
sed -n '252,259p' crates/codebase-chat-core/src/kind.rs
|
||||
sed -n '252,259p' crates/meridian-core/src/kind.rs
|
||||
|
||||
# Standing rule for every phase that adds a kind
|
||||
just check-kinds
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
> **Status** — production candidate · browser and desktop surfaces · server flag
|
||||
> `CODEBASE_CHAT_CONTROL_COMMUNITIES_UI` · tracked by
|
||||
> `MERIDIAN_CONTROL_COMMUNITIES_UI` · tracked by
|
||||
> [`epic-community-registration-production.md`](../epics/epic-community-registration-production.md)
|
||||
|
||||
# Feature: Community Registration
|
||||
|
||||
Community registration is the account-shaped control-plane surface for creating
|
||||
and managing relay communities. It is served by `codebase-chat-control-plane` at
|
||||
and managing relay communities. It is served by `meridian-control-plane` at
|
||||
`{public_origin}{api_base_path}/communities`; no third-party registration service
|
||||
or identity provider is assumed.
|
||||
|
||||
|
|
@ -45,12 +45,12 @@ Names never encode ownership.
|
|||
|
||||
- Sign in and bootstrap a browser credential.
|
||||
- Connect a Nostr identity by sending a kind `24243` challenge to the desktop
|
||||
through `codebasechat://nostr-bind`; the secret key never enters the browser.
|
||||
through `meridian://nostr-bind`; the secret key never enters the browser.
|
||||
- Check name availability, create a community, copy/open its relay address,
|
||||
archive it, and restore it.
|
||||
- Disconnect the identity only after all communities have been transferred.
|
||||
- Disable the browser page entirely with
|
||||
`CODEBASE_CHAT_CONTROL_COMMUNITIES_UI=off` (the API remains available).
|
||||
`MERIDIAN_CONTROL_COMMUNITIES_UI=off` (the API remains available).
|
||||
|
||||
The responsive browser page works at narrow viewports, but this is not Flutter
|
||||
mobile parity. Identity connection and community opening currently require the
|
||||
|
|
@ -73,15 +73,15 @@ unbounded request admission. The current gates are:
|
|||
|
||||
```bash
|
||||
. ./bin/activate-hermit
|
||||
CODEBASE_CHAT_TEST_DATABASE_URL=postgres://... \
|
||||
cargo test -p codebase-chat-control-plane --all-targets --no-fail-fast
|
||||
cargo clippy -p codebase-chat-control-plane --all-targets -- -D warnings
|
||||
cargo fmt --check -p codebase-chat-control-plane
|
||||
MERIDIAN_TEST_DATABASE_URL=postgres://... \
|
||||
cargo test -p meridian-control-plane --all-targets --no-fail-fast
|
||||
cargo clippy -p meridian-control-plane --all-targets -- -D warnings
|
||||
cargo fmt --check -p meridian-control-plane
|
||||
pnpm -C desktop check
|
||||
CONTROL_PLANE_URL=http://127.0.0.1:8090 \
|
||||
pnpm -C desktop exec playwright test \
|
||||
--config tests/control-plane/playwright.config.mjs
|
||||
bash deploy/charts/codebase-chat-control-plane/tests/render.sh
|
||||
bash deploy/charts/meridian-control-plane/tests/render.sh
|
||||
```
|
||||
|
||||
The Playwright suite signs the real binding event, creates, archives, restores,
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ second-resolution and 45002 is not replaceable, so a user correcting a misclick
|
|||
within one second produces two votes with identical timestamps. The first
|
||||
implementation broke the tie on event id; the second "fixed" it by breaking on
|
||||
input-array position, on the assumption that the relay returns insertion order.
|
||||
**It does not** — `codebase-chat-db/src/event.rs` orders
|
||||
**It does not** — `meridian-db/src/event.rs` orders
|
||||
`created_at DESC, id ASC`, so array position resolved right back to "largest
|
||||
SHA-256 id wins". The two implementations were behaviorally identical.
|
||||
|
||||
|
|
@ -114,7 +114,7 @@ explicitly rather than by continued drift.
|
|||
|
||||
## Current State
|
||||
|
||||
**Protocol** — `crates/codebase-chat-core/src/kind.rs:487-495`. The comment
|
||||
**Protocol** — `crates/meridian-core/src/kind.rs:487-495`. The comment
|
||||
records the history: v1 used the addressable range 30001–30003, which was
|
||||
wrong; forum kinds now live at 45001–45003.
|
||||
|
||||
|
|
@ -157,7 +157,7 @@ Tests: `mobile/test/features/forum/forum_models_test.dart`,
|
|||
|
||||
**CLI** — `channels create --type forum` (`commands/channels.rs:294,321`),
|
||||
`messages vote --event --direction` (`lib.rs:497`, implemented at
|
||||
`commands/messages.rs:843-865` via `codebase_chat_sdk::build_vote`).
|
||||
`commands/messages.rs:843-865` via `meridian_sdk::build_vote`).
|
||||
|
||||
## Gap Register
|
||||
|
||||
|
|
@ -368,7 +368,7 @@ just desktop-typecheck
|
|||
just desktop-e2e-smoke
|
||||
just mobile-check
|
||||
just mobile-test
|
||||
cargo test -p codebase-chat-relay forum
|
||||
cargo test -p meridian-relay forum
|
||||
```
|
||||
|
||||
Confirm the vote kind is no longer orphaned:
|
||||
|
|
@ -383,5 +383,5 @@ End-to-end through the CLI, which already works and is the reference behavior
|
|||
the UIs must match:
|
||||
|
||||
```bash
|
||||
codebase-chat --format compact messages vote --event <hex> --direction up
|
||||
meridian --format compact messages vote --event <hex> --direction up
|
||||
```
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
# Feature: Granular Permissions
|
||||
|
||||
Codebase Chat authorizes every moderation action against a three-value string
|
||||
Meridian authorizes every moderation action against a three-value string
|
||||
role — `owner`, `admin`, `member` — stored in `relay_members.role`. There is no
|
||||
per-channel override, no capability decomposition, and no way to grant one
|
||||
person one power. The reference implementation resolves the same questions
|
||||
|
|
@ -24,9 +24,9 @@ bits* and cannot be specified coherently until this model exists. Read this
|
|||
first.
|
||||
|
||||
The defining artifact: **kind 39003 `KIND_NIP29_GROUP_ROLES` is orphaned.** It
|
||||
is declared at `crates/codebase-chat-core/src/kind.rs:368`, listed as
|
||||
is declared at `crates/meridian-core/src/kind.rs:368`, listed as
|
||||
addressable at `:621`, and range-matched for `d`-tag derivation at
|
||||
`crates/codebase-chat-relay/src/handlers/event.rs:41`. Nothing else in the
|
||||
`crates/meridian-relay/src/handlers/event.rs:41`. Nothing else in the
|
||||
repository reads or writes it — not the relay, not the SDK, not the CLI, not
|
||||
any client. The slot NIP-29 reserves for a role system is allocated and empty.
|
||||
|
||||
|
|
@ -35,7 +35,7 @@ any client. The slot NIP-29 reserves for a role system is allocated and empty.
|
|||
**Introduce a capability set, not a permission bitfield.**
|
||||
|
||||
The reference packs permissions into `u64` bitflags because its transport is a
|
||||
REST API with a fixed schema. Codebase Chat's transport is Nostr events, where
|
||||
REST API with a fixed schema. Meridian's transport is Nostr events, where
|
||||
the natural encoding is tags. A bitfield forces a registry of bit positions that
|
||||
can never be reordered and is unreadable in a raw event; a tag list
|
||||
(`["capability", "message:delete"]`) is self-describing, extends without
|
||||
|
|
@ -48,13 +48,13 @@ already carrying numbering scars, and inheriting them buys nothing.
|
|||
**Rejected: leaving the three-role model and adding special cases.** That is
|
||||
the current trajectory. `moderation_authz.rs` already encodes "channel role
|
||||
covers only delete and kick" as a hardcoded match arm
|
||||
(`crates/codebase-chat-relay/src/handlers/moderation_authz.rs:173-177`, test at
|
||||
(`crates/meridian-relay/src/handlers/moderation_authz.rs:173-177`, test at
|
||||
`:296`). Every new power adds an arm. The reference's per-channel overlay exists
|
||||
precisely because that approach does not scale past about five actions.
|
||||
|
||||
**Deliberate divergence: no role *rank* ordering in phase 1.** The reference has
|
||||
`roles_edit_positions.rs` (5.8K) implementing rank comparison so a moderator
|
||||
cannot ban someone above them. Codebase Chat gets this today for free from the
|
||||
cannot ban someone above them. Meridian gets this today for free from the
|
||||
flat owner > admin > member ladder, and the guard rail is already written
|
||||
(`moderation_authz.rs:102` reads the target's role "only for the admin guard
|
||||
rail"). Ranked custom roles are Phase 4 and may never be needed.
|
||||
|
|
@ -68,7 +68,7 @@ rail"). Ranked custom roles are Phase 4 and may never be needed.
|
|||
3. A community can grant "delete messages in #support" without granting `admin`.
|
||||
4. The existing `owner`/`admin`/`member` roles keep working unchanged, expressed
|
||||
as built-in capability bundles.
|
||||
5. Capability denial is auditable — `codebase-chat-audit` records which
|
||||
5. Capability denial is auditable — `meridian-audit` records which
|
||||
capability was missing.
|
||||
|
||||
## Non-Goals
|
||||
|
|
@ -85,9 +85,9 @@ rail"). Ranked custom roles are Phase 4 and may never be needed.
|
|||
|
||||
## Current State
|
||||
|
||||
**Codebase Chat — authorization is a three-arm match.**
|
||||
**Meridian — authorization is a three-arm match.**
|
||||
|
||||
`crates/codebase-chat-relay/src/handlers/moderation_authz.rs:62-69`:
|
||||
`crates/meridian-relay/src/handlers/moderation_authz.rs:62-69`:
|
||||
|
||||
```rust
|
||||
pub enum ModerationAuthority {
|
||||
|
|
@ -105,7 +105,7 @@ Validation lives in `relay_admin.rs:276-278` — `if role != "admin" && role !=
|
|||
"member"` — i.e. the closed set is enforced by string comparison at the write
|
||||
site, not by a type.
|
||||
|
||||
| Question | Reference answers with | Codebase Chat answers with |
|
||||
| Question | Reference answers with | Meridian answers with |
|
||||
| --- | --- | --- |
|
||||
| May X delete a message? | `ManageMessages` bit, channel overlay | `ModerationAuthority` match arm |
|
||||
| May X ban? | `BanMembers` bit | `owner`/`admin` string compare |
|
||||
|
|
@ -131,8 +131,8 @@ Overlays are set by four routes — `servers/permissions_set.rs`,
|
|||
`servers/permissions_set_default.rs`, `channels/permissions_set.rs`,
|
||||
`channels/permissions_set_default.rs` — each writing an allow/deny pair.
|
||||
|
||||
**What Codebase Chat already has that the reference does not.** The audit
|
||||
hash-chain (`codebase-chat-audit`) has no reference counterpart;
|
||||
**What Meridian already has that the reference does not.** The audit
|
||||
hash-chain (`meridian-audit`) has no reference counterpart;
|
||||
`ViewAuditLogs` is a bit there and a subsystem here. Do not regress it.
|
||||
|
||||
## Gap Register
|
||||
|
|
@ -144,7 +144,7 @@ hash-chain (`codebase-chat-audit`) has no reference counterpart;
|
|||
| P3 | Each new moderated action needs a new match arm. `ChannelRole` is already special-cased to "delete and kick" in a match arm rather than a data lookup. | `moderation_authz.rs:173-177`, test `channel_role_covers_only_delete_and_kick` at `:296` | high |
|
||||
| P4 | `relay_members.role` is an unvalidated `String` at the read site; the closed set is enforced only by string comparison at the write site. | `moderation_authz.rs:96-100` vs `relay_admin.rs:276-278` | medium |
|
||||
| P5 | No per-channel authorization overlay. A community moderator is a moderator everywhere. | absence of any channel-scoped grant table in `migrations/` | medium |
|
||||
| P6 | Capability denials are not distinguishable in the audit log — a denial records the action, not the missing capability. | `codebase-chat-audit` has no capability field | low |
|
||||
| P6 | Capability denials are not distinguishable in the audit log — a denial records the action, not the missing capability. | `meridian-audit` has no capability field | low |
|
||||
|
||||
## Maturation Plan
|
||||
|
||||
|
|
@ -172,8 +172,8 @@ audit:read
|
|||
**Task 1.2: Failing test for capability resolution**
|
||||
|
||||
Files:
|
||||
- Create: `crates/codebase-chat-core/src/capability.rs`
|
||||
- Modify: `crates/codebase-chat-core/src/lib.rs`
|
||||
- Create: `crates/meridian-core/src/capability.rs`
|
||||
- Modify: `crates/meridian-core/src/lib.rs`
|
||||
|
||||
```rust
|
||||
#[test]
|
||||
|
|
@ -191,7 +191,7 @@ fn unknown_role_grants_nothing() {
|
|||
}
|
||||
```
|
||||
|
||||
Run `cargo test -p codebase-chat-core capability` — expected FAIL. Implement,
|
||||
Run `cargo test -p meridian-core capability` — expected FAIL. Implement,
|
||||
re-run, expect PASS. The second test is the one that matters: an unrecognized
|
||||
role string must be inert, not permissive. Today an unknown string falls to the
|
||||
`_ =>` arm at `moderation_authz.rs:173` — verify what that arm actually does
|
||||
|
|
@ -200,8 +200,8 @@ before assuming it is safe.
|
|||
**Task 1.3: Give 39003 a schema**
|
||||
|
||||
Files:
|
||||
- Modify: `crates/codebase-chat-core/src/kind.rs`
|
||||
- Modify: `crates/codebase-chat-relay/src/handlers/ingest.rs`
|
||||
- Modify: `crates/meridian-core/src/kind.rs`
|
||||
- Modify: `crates/meridian-relay/src/handlers/ingest.rs`
|
||||
|
||||
A 39003 event is `d` = role name, plus one `capability` tag per grant:
|
||||
|
||||
|
|
@ -221,7 +221,7 @@ does nothing.
|
|||
**Task 2.1: Make the role a type, not a string**
|
||||
|
||||
Files:
|
||||
- Modify: `crates/codebase-chat-relay/src/handlers/moderation_authz.rs`
|
||||
- Modify: `crates/meridian-relay/src/handlers/moderation_authz.rs`
|
||||
|
||||
Parse `relay_members.role` into an enum at the read site (`:96-100`). The
|
||||
`unwrap_or("")` at `relay_admin.rs:225-228` currently makes "no membership row"
|
||||
|
|
@ -231,7 +231,7 @@ rather than incidental.
|
|||
**Task 2.2: Replace the match arms**
|
||||
|
||||
Files:
|
||||
- Modify: `crates/codebase-chat-relay/src/handlers/moderation_authz.rs`
|
||||
- Modify: `crates/meridian-relay/src/handlers/moderation_authz.rs`
|
||||
|
||||
`authorize(actor, action, target)` resolves the actor's capability set once, then
|
||||
checks `caps.has(action.capability())`. `ModerationAuthority` stays as the
|
||||
|
|
@ -246,7 +246,7 @@ today's behavior exactly.
|
|||
|
||||
Files:
|
||||
- Create: `migrations/<timestamp>_capability_grants.sql`
|
||||
- Modify: `crates/codebase-chat-db/src/lib.rs`
|
||||
- Modify: `crates/meridian-db/src/lib.rs`
|
||||
|
||||
Forward-only, per `migrations/AGENTS.md`. Resolution order: channel grant, then
|
||||
community role bundle, then deny.
|
||||
|
|
@ -256,17 +256,17 @@ community role bundle, then deny.
|
|||
**Task 3.1: Record the missing capability**
|
||||
|
||||
Files:
|
||||
- Modify: `crates/codebase-chat-audit/src/lib.rs`
|
||||
- Modify: `crates/meridian-audit/src/lib.rs`
|
||||
|
||||
A denial entry names the capability that was absent.
|
||||
|
||||
**Task 3.2: CLI before UI**
|
||||
|
||||
Files:
|
||||
- Modify: `crates/codebase-chat-cli/src/commands/` — new `roles` subcommand
|
||||
- Modify: `crates/meridian-cli/src/commands/` — new `roles` subcommand
|
||||
|
||||
Per the root guide, agent-facing operations land in `codebase-chat-cli` first.
|
||||
`codebase-chat roles create --name support-mod --capability message:delete
|
||||
Per the root guide, agent-facing operations land in `meridian-cli` first.
|
||||
`meridian roles create --name support-mod --capability message:delete
|
||||
--channel <id>`. This is the reference behavior the UI must later match, and it
|
||||
makes Phase 4 optional rather than blocking.
|
||||
|
||||
|
|
@ -282,7 +282,7 @@ Checked against
|
|||
|
||||
- [ ] Protocol complete — 39003 has no reader or writer (P1). **Blocker.**
|
||||
- [ ] No orphaned kinds — same
|
||||
- [ ] Agent surface — no `roles` subcommand in `codebase-chat-cli`
|
||||
- [ ] Agent surface — no `roles` subcommand in `meridian-cli`
|
||||
- [ ] Failure paths — unknown-role behavior undocumented (P4)
|
||||
- [ ] Docs — no `docs/nips/NIP-CAP.md`
|
||||
- [ ] Platform parity — n/a until Phase 4
|
||||
|
|
@ -291,8 +291,8 @@ Checked against
|
|||
## Verification
|
||||
|
||||
```bash
|
||||
cargo test -p codebase-chat-core capability
|
||||
cargo test -p codebase-chat-relay moderation_authz
|
||||
cargo test -p meridian-core capability
|
||||
cargo test -p meridian-relay moderation_authz
|
||||
just test # integration; needs Postgres + Dragonfly
|
||||
just ci
|
||||
```
|
||||
|
|
@ -309,5 +309,5 @@ what else has landed.
|
|||
Confirm no behavior regression on the built-in ladder:
|
||||
|
||||
```bash
|
||||
cargo test -p codebase-chat-relay channel_role_covers_only_delete_and_kick
|
||||
cargo test -p meridian-relay channel_role_covers_only_delete_and_kick
|
||||
```
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
# Feature: Generic Link Embeds
|
||||
|
||||
Paste a GitHub PR link into Codebase Chat and you get a rich preview. Paste a
|
||||
Paste a GitHub PR link into Meridian and you get a rich preview. Paste a
|
||||
link to anything else — a blog post, a news article, a design doc on a domain
|
||||
nobody allowlisted — and you get a bare URL.
|
||||
|
||||
|
|
@ -49,7 +49,7 @@ readable by every client without a new API.
|
|||
|
||||
**Rejected: porting `january` as a separate service.** The reference splits it
|
||||
out because its architecture is already multi-service (delta, bonfire, autumn,
|
||||
january, gifbox, pushd, crond). Codebase Chat runs one relay binary. A second
|
||||
january, gifbox, pushd, crond). Meridian runs one relay binary. A second
|
||||
deployable to parse HTML would be the largest operational change in this parity
|
||||
set for the smallest feature.
|
||||
|
||||
|
|
@ -83,7 +83,7 @@ is the fallback, not the replacement.
|
|||
the extension path.
|
||||
- **No media proxying.** The reference's `/proxy` route
|
||||
(`january/src/api.rs:15`) re-serves remote images through its own host.
|
||||
Codebase Chat has Blossom for media it owns; proxying arbitrary remote images
|
||||
Meridian has Blossom for media it owns; proxying arbitrary remote images
|
||||
is a separate bandwidth and abuse conversation.
|
||||
- **No embeds in DMs in phase 1.** Unfurling a link in a private conversation
|
||||
tells the relay operator what was linked. Ship it opt-in later, or not at all.
|
||||
|
|
@ -95,7 +95,7 @@ is the fallback, not the replacement.
|
|||
|
||||
## Current State
|
||||
|
||||
**Codebase Chat — a nine-entry pattern matcher, desktop-only.**
|
||||
**Meridian — a nine-entry pattern matcher, desktop-only.**
|
||||
|
||||
`desktop/src/shared/lib/linkPreview.ts:1-10` — the complete supported set:
|
||||
|
||||
|
|
@ -134,7 +134,7 @@ Mobile and web have nothing:
|
|||
grep -rln "linkPreview\|link_preview\|LinkPreview" mobile/lib web/src # → no output
|
||||
```
|
||||
|
||||
| Capability | Codebase Chat | Reference |
|
||||
| Capability | Meridian | Reference |
|
||||
| --- | --- | --- |
|
||||
| Arbitrary URL title | ❌ | ✅ `og:title` |
|
||||
| Description | ❌ | ✅ `og:description` |
|
||||
|
|
@ -187,7 +187,7 @@ building it first creates pressure to ship the fetcher unguarded.
|
|||
**Task 1.1: Failing test for URL admission**
|
||||
|
||||
Files:
|
||||
- Create: `crates/codebase-chat-relay/src/unfurl/guard.rs`
|
||||
- Create: `crates/meridian-relay/src/unfurl/guard.rs`
|
||||
|
||||
```rust
|
||||
#[test]
|
||||
|
|
@ -213,7 +213,7 @@ fn rejects_redirect_into_private_space() {
|
|||
}
|
||||
```
|
||||
|
||||
Run `cargo test -p codebase-chat-relay unfurl::guard` — expected FAIL.
|
||||
Run `cargo test -p meridian-relay unfurl::guard` — expected FAIL.
|
||||
Implement, re-run, expect PASS.
|
||||
|
||||
The third test is the one that catches the real exploit. Checking only the
|
||||
|
|
@ -224,11 +224,11 @@ hop, and cap redirects.
|
|||
**Task 1.2: Budgets**
|
||||
|
||||
Files:
|
||||
- Modify: `crates/codebase-chat-relay/src/unfurl/mod.rs`
|
||||
- Modify: `crates/codebase-chat-relay/src/config.rs`
|
||||
- Modify: `crates/meridian-relay/src/unfurl/mod.rs`
|
||||
- Modify: `crates/meridian-relay/src/config.rs`
|
||||
|
||||
Response size cap, total timeout, redirect cap, per-community rate limit.
|
||||
Env-configured alongside the existing `CODEBASE_CHAT_RATE_LIMIT_*` knobs
|
||||
Env-configured alongside the existing `MERIDIAN_RATE_LIMIT_*` knobs
|
||||
(`config.rs:305-329`) — this *is* an operator anti-abuse control, unlike
|
||||
slowmode (see [`feature-channel-slowmode.md`](./feature-channel-slowmode.md)),
|
||||
so it belongs there.
|
||||
|
|
@ -240,7 +240,7 @@ Read only the `<head>`. A 4 GB response should cost 8 KB.
|
|||
**Task 2.1: Failing test for the fallback chains**
|
||||
|
||||
Files:
|
||||
- Create: `crates/codebase-chat-relay/src/unfurl/opengraph.rs`
|
||||
- Create: `crates/meridian-relay/src/unfurl/opengraph.rs`
|
||||
|
||||
Port the reference's chains exactly (`website_embed.rs:48-137`) and test each
|
||||
fallback step — a chain that silently stops at `og:image` and never tries
|
||||
|
|
@ -263,7 +263,7 @@ fn missing_metadata_yields_none_not_empty_string() { /* ... */ }
|
|||
**Task 2.2: Allocate the kind**
|
||||
|
||||
Files:
|
||||
- Modify: `crates/codebase-chat-core/src/kind.rs`
|
||||
- Modify: `crates/meridian-core/src/kind.rs`
|
||||
|
||||
Addressable, `d` = hash of the normalized URL. Confirm the number is unclaimed
|
||||
before taking it, and **do not merge the constant without a reader** — three
|
||||
|
|
@ -273,7 +273,7 @@ it).
|
|||
**Task 2.3: Publish on ingest**
|
||||
|
||||
Files:
|
||||
- Modify: `crates/codebase-chat-relay/src/handlers/ingest.rs`
|
||||
- Modify: `crates/meridian-relay/src/handlers/ingest.rs`
|
||||
|
||||
Extract URLs from 40002, enqueue asynchronously. Never block message ingest on
|
||||
an outbound fetch — a slow remote host must not slow the channel.
|
||||
|
|
@ -323,7 +323,7 @@ Files:
|
|||
## Verification
|
||||
|
||||
```bash
|
||||
cargo test -p codebase-chat-relay unfurl
|
||||
cargo test -p meridian-relay unfurl
|
||||
just test
|
||||
just desktop-test
|
||||
just desktop-e2e-smoke
|
||||
|
|
@ -334,7 +334,7 @@ just ci
|
|||
Confirm the SSRF guard runs on every redirect hop, not just admission:
|
||||
|
||||
```bash
|
||||
cargo test -p codebase-chat-relay rejects_redirect_into_private_space
|
||||
cargo test -p meridian-relay rejects_redirect_into_private_space
|
||||
```
|
||||
|
||||
Confirm no client-side fetch remains:
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
# Feature: Per-Community Member Profiles
|
||||
|
||||
One person, several communities, one name. Codebase Chat identity is the global
|
||||
One person, several communities, one name. Meridian identity is the global
|
||||
Nostr `kind:0` profile: change your display name for a work community and it
|
||||
changes everywhere you have ever posted, retroactively, including in communities
|
||||
run by people you have never met.
|
||||
|
|
@ -80,7 +80,7 @@ four precedence levels on every message render.
|
|||
- **No global profile changes.** `kind:0` semantics are untouched.
|
||||
- **No per-channel names.** Community scope only. The reference is per-server
|
||||
too.
|
||||
- **No name history UI.** `codebase-chat-audit` records the change; surfacing a
|
||||
- **No name history UI.** `meridian-audit` records the change; surfacing a
|
||||
timeline is not this feature.
|
||||
- **No uniqueness enforcement.** Two members may pick the same display name;
|
||||
the npub remains the identity. Enforcing uniqueness would require a registry
|
||||
|
|
@ -90,19 +90,19 @@ four precedence levels on every message render.
|
|||
|
||||
## Current State
|
||||
|
||||
**Codebase Chat — one global identity, no overlay.**
|
||||
**Meridian — one global identity, no overlay.**
|
||||
|
||||
```bash
|
||||
grep -ril "nickname" crates desktop/src mobile/lib web/src # → no output
|
||||
```
|
||||
|
||||
Identity resolution today is `kind:0` → npub. `KIND_PROFILE` is
|
||||
`crates/codebase-chat-core/src/kind.rs:11` (kind 0), replaceable per
|
||||
`crates/meridian-core/src/kind.rs:11` (kind 0), replaceable per
|
||||
`is_replaceable` at `:701-705`.
|
||||
|
||||
The near-miss is kind 9033 `RELAY_ADMIN_SET_WORKSPACE_PROFILE`
|
||||
(`kind.rs:335`). Despite the name it sets the **community's own icon**, not any
|
||||
member's profile — `crates/codebase-chat-relay/src/handlers/relay_admin.rs:232-251`
|
||||
member's profile — `crates/meridian-relay/src/handlers/relay_admin.rs:232-251`
|
||||
reads a single `icon` tag and calls `set_community_icon`. It is community
|
||||
branding, and it is admin/owner-gated at `:233`.
|
||||
|
||||
|
|
@ -115,7 +115,7 @@ branding, and it is admin/owner-gated at `:233`.
|
|||
| Relay | replaceable store | — |
|
||||
| Desktop | `features/profile/` | — |
|
||||
| Mobile | `mobile/lib/features/profile/` | — |
|
||||
| CLI | `codebase-chat users` | — |
|
||||
| CLI | `meridian users` | — |
|
||||
|
||||
**Reference — nickname on the membership record.**
|
||||
|
||||
|
|
@ -158,7 +158,7 @@ override, because a name is required for legibility and an avatar is not.
|
|||
|
||||
Files:
|
||||
- Create: `docs/nips/NIP-MEMBER-PROFILE.md`
|
||||
- Modify: `crates/codebase-chat-core/src/kind.rs`
|
||||
- Modify: `crates/meridian-core/src/kind.rs`
|
||||
|
||||
Two addressable kinds in 30000–39999 (`PARAM_REPLACEABLE_KIND_MIN/MAX`,
|
||||
`kind.rs`), `d` = community id:
|
||||
|
|
@ -175,7 +175,7 @@ pub const KIND_MEMBER_PROFILE_OVERRIDE: u32 = 30179;
|
|||
claiming them:
|
||||
|
||||
```bash
|
||||
grep -n "30178\|30179" crates/codebase-chat-core/src/kind.rs
|
||||
grep -n "30178\|30179" crates/meridian-core/src/kind.rs
|
||||
```
|
||||
|
||||
Also fix N4 in the same pass — extend the doc comment on 9033 to say it sets
|
||||
|
|
@ -184,7 +184,7 @@ community branding and is *not* a member profile.
|
|||
**Task 1.2: Failing test for resolution order**
|
||||
|
||||
Files:
|
||||
- Create: `crates/codebase-chat-core/src/member_profile.rs`
|
||||
- Create: `crates/meridian-core/src/member_profile.rs`
|
||||
|
||||
```rust
|
||||
#[test]
|
||||
|
|
@ -206,17 +206,17 @@ fn falls_through_to_npub_when_nothing_set() {
|
|||
}
|
||||
```
|
||||
|
||||
Run `cargo test -p codebase-chat-core member_profile` — expected FAIL.
|
||||
Run `cargo test -p meridian-core member_profile` — expected FAIL.
|
||||
Implement, re-run, expect PASS.
|
||||
|
||||
Put resolution in `codebase-chat-core` so the relay, CLI, and SDK share one
|
||||
Put resolution in `meridian-core` so the relay, CLI, and SDK share one
|
||||
implementation. Every client reimplementing a four-level precedence chain is
|
||||
four chances to disagree about who someone is.
|
||||
|
||||
**Task 1.3: Ingest validation**
|
||||
|
||||
Files:
|
||||
- Modify: `crates/codebase-chat-relay/src/handlers/ingest.rs`
|
||||
- Modify: `crates/meridian-relay/src/handlers/ingest.rs`
|
||||
|
||||
30178: author must be a member of the `d` community. 30179: author must hold the
|
||||
manage-nicknames capability, and the target `p` tag is required. Length-bound
|
||||
|
|
@ -229,13 +229,13 @@ limit.
|
|||
**Task 2.1: CLI first**
|
||||
|
||||
Files:
|
||||
- Modify: `crates/codebase-chat-cli/src/commands/users.rs`
|
||||
- Modify: `crates/codebase-chat-cli/src/lib.rs`
|
||||
- Modify: `crates/meridian-cli/src/commands/users.rs`
|
||||
- Modify: `crates/meridian-cli/src/lib.rs`
|
||||
|
||||
```
|
||||
codebase-chat users set-community-profile --community <id> --name "..." [--avatar <url>]
|
||||
codebase-chat users clear-community-profile --community <id>
|
||||
codebase-chat moderation override-name --community <id> --pubkey <hex> --name "..."
|
||||
meridian users set-community-profile --community <id> --name "..." [--avatar <url>]
|
||||
meridian users clear-community-profile --community <id>
|
||||
meridian moderation override-name --community <id> --pubkey <hex> --name "..."
|
||||
```
|
||||
|
||||
**Task 2.2: Desktop resolution at the render path**
|
||||
|
|
@ -312,8 +312,8 @@ Files:
|
|||
## Verification
|
||||
|
||||
```bash
|
||||
cargo test -p codebase-chat-core member_profile
|
||||
cargo test -p codebase-chat-relay member_profile
|
||||
cargo test -p meridian-core member_profile
|
||||
cargo test -p meridian-relay member_profile
|
||||
just test
|
||||
just desktop-test
|
||||
just desktop-e2e-smoke
|
||||
|
|
@ -324,7 +324,7 @@ just ci
|
|||
Confirm the three resolvers agree. All three must encode the same precedence:
|
||||
|
||||
```bash
|
||||
grep -rn "npub1" crates/codebase-chat-core/src/member_profile.rs \
|
||||
grep -rn "npub1" crates/meridian-core/src/member_profile.rs \
|
||||
desktop/src/features/profile/lib/resolveMemberProfile.ts \
|
||||
mobile/lib/features/profile/
|
||||
```
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ it. It is how bridges work. A Matrix or IRC bridge holds one account and relays
|
|||
messages from hundreds of people; without masquerade every bridged message
|
||||
appears to come from "bridge-bot", and the conversation is unreadable.
|
||||
|
||||
Codebase Chat has no equivalent. It also has the strictest possible ground truth
|
||||
Meridian has no equivalent. It also has the strictest possible ground truth
|
||||
to build on — every event carries a signature over its author's pubkey, so a
|
||||
display override can never be mistaken for an authorship claim by any client
|
||||
that checks. That property makes masquerade *safer* here than in the reference,
|
||||
|
|
@ -47,7 +47,7 @@ message, and the real author is always one hover away.
|
|||
|
||||
**Non-negotiable: the real author must be discoverable without leaving the
|
||||
message.** The reference makes this a client convention. Here it is a
|
||||
requirement of the spec, because Codebase Chat is a work tool where "who
|
||||
requirement of the spec, because Meridian is a work tool where "who
|
||||
actually said this" is an accountability question. A masqueraded message
|
||||
renders with a persistent marker and reveals the true pubkey on hover or tap.
|
||||
A client that hides the real author is non-conformant.
|
||||
|
|
@ -67,7 +67,7 @@ a first-class product rather than an integration.
|
|||
**Deliberate divergence: `masquerade_colour` requires the same capability as the
|
||||
other two.** The reference gates colour behind `ManageRole`
|
||||
(`models/src/v0/messages.rs:155`) because colour implies role membership in its
|
||||
UI. Codebase Chat has no role-colour convention, so the extra gate protects
|
||||
UI. Meridian has no role-colour convention, so the extra gate protects
|
||||
nothing and adds a second authorization path to test.
|
||||
|
||||
## Goals
|
||||
|
|
@ -91,28 +91,28 @@ nothing and adds a second authorization path to test.
|
|||
|
||||
## Current State
|
||||
|
||||
**Codebase Chat — absent.**
|
||||
**Meridian — absent.**
|
||||
|
||||
```bash
|
||||
grep -rin "masquerade" crates desktop/src mobile/lib web/src
|
||||
```
|
||||
|
||||
Three hits, all the English word in unrelated comments:
|
||||
`crates/codebase-chat-relay/src/conformance/mod.rs:185`,
|
||||
`crates/codebase-chat-db/src/replica_fence.rs:47`,
|
||||
`crates/meridian-relay/src/conformance/mod.rs:185`,
|
||||
`crates/meridian-db/src/replica_fence.rs:47`,
|
||||
`desktop/src/features/onboarding/welcomeCanvas.ts:33`.
|
||||
|
||||
Message identity today is `event.pubkey` → `kind:0` → npub, with no override at
|
||||
any layer.
|
||||
|
||||
The adjacent surface is webhooks, which exist but are workflow triggers, not
|
||||
message identity. `crates/codebase-chat-relay/src/api/bridge.rs:1817`
|
||||
message identity. `crates/meridian-relay/src/api/bridge.rs:1817`
|
||||
`workflow_webhook` authenticates by shared secret (`:1860`, header preferred
|
||||
over query param because proxies log query strings) and fires a workflow. It
|
||||
does not post a message under a custom identity, and there is no code path that
|
||||
does.
|
||||
|
||||
| Capability | Reference | Codebase Chat |
|
||||
| Capability | Reference | Meridian |
|
||||
| --- | --- | --- |
|
||||
| Post under a custom name | `Masquerade` bit 28 | — |
|
||||
| Webhook posts as named service | webhook + masquerade | workflow trigger only |
|
||||
|
|
@ -143,7 +143,7 @@ from the presence of the field. That is the part this spec tightens.
|
|||
| --- | --- | --- | --- |
|
||||
| M1 | No display override exists, so a bridge cannot relay legibly — every bridged message appears authored by the bridge account. | `grep -rin masquerade` returns 3 unrelated comment hits | medium |
|
||||
| M2 | Webhooks cannot post under a service identity. A CI notification is indistinguishable from a human message by the same relay account. | `api/bridge.rs:1817` fires workflows; no message-identity path | medium |
|
||||
| M3 | The reference has no server-side masquerade marker — detection depends entirely on the client noticing a field. Porting as-is imports that weakness. | absence of a marker in `models/src/v0/messages.rs:144-158` | medium (design risk, not a Codebase Chat defect) |
|
||||
| M3 | The reference has no server-side masquerade marker — detection depends entirely on the client noticing a field. Porting as-is imports that weakness. | absence of a marker in `models/src/v0/messages.rs:144-158` | medium (design risk, not a Meridian defect) |
|
||||
| M4 | No capability exists to gate it. | blocked on P1/P2 in `feature-granular-permissions.md` | low (blocking) |
|
||||
| M5 | Moderation acts on `event.pubkey`, which is correct and must be verified to *stay* correct once a display name diverges from the author. | `moderation_authz.rs` resolves by pubkey throughout | low (regression risk) |
|
||||
|
||||
|
|
@ -174,8 +174,8 @@ absence of a stated rule.
|
|||
**Task 1.2: Failing test for extraction and validation**
|
||||
|
||||
Files:
|
||||
- Create: `crates/codebase-chat-core/src/masquerade.rs`
|
||||
- Modify: `crates/codebase-chat-core/src/lib.rs`
|
||||
- Create: `crates/meridian-core/src/masquerade.rs`
|
||||
- Modify: `crates/meridian-core/src/lib.rs`
|
||||
|
||||
```rust
|
||||
#[test]
|
||||
|
|
@ -199,7 +199,7 @@ fn absent_tags_yield_none() {
|
|||
}
|
||||
```
|
||||
|
||||
Run `cargo test -p codebase-chat-core masquerade` — expected FAIL. Implement,
|
||||
Run `cargo test -p meridian-core masquerade` — expected FAIL. Implement,
|
||||
re-run, expect PASS.
|
||||
|
||||
Match the reference's 1–32 and 1–256 bounds
|
||||
|
|
@ -211,7 +211,7 @@ a bridge to find it.
|
|||
**Task 1.3: Ingest gate**
|
||||
|
||||
Files:
|
||||
- Modify: `crates/codebase-chat-relay/src/handlers/ingest.rs`
|
||||
- Modify: `crates/meridian-relay/src/handlers/ingest.rs`
|
||||
|
||||
Reject masquerade tags on kind 40002 from an author without the capability, and
|
||||
on any other kind unconditionally. Rejecting is right: accepting-and-ignoring
|
||||
|
|
@ -221,7 +221,7 @@ some other client will render.
|
|||
**Task 1.4: Verify moderation is unaffected (closes M5)**
|
||||
|
||||
Files:
|
||||
- Modify: `crates/codebase-chat-relay/src/handlers/moderation_authz.rs` (tests
|
||||
- Modify: `crates/meridian-relay/src/handlers/moderation_authz.rs` (tests
|
||||
only)
|
||||
|
||||
Add a case: a masqueraded message is moderated by real author, and a ban on the
|
||||
|
|
@ -234,10 +234,10 @@ on first run. If it does not, masquerade has leaked into authorization and Phase
|
|||
**Task 2.1: CLI first**
|
||||
|
||||
Files:
|
||||
- Modify: `crates/codebase-chat-cli/src/commands/messages.rs`
|
||||
- Modify: `crates/codebase-chat-cli/src/lib.rs`
|
||||
- Modify: `crates/meridian-cli/src/commands/messages.rs`
|
||||
- Modify: `crates/meridian-cli/src/lib.rs`
|
||||
|
||||
`codebase-chat messages send --channel <uuid> --content "..." --as-name "CI"
|
||||
`meridian messages send --channel <uuid> --content "..." --as-name "CI"
|
||||
--as-avatar <url>`. Reference behavior for the UIs, and immediately useful to
|
||||
the webhook case without any UI work.
|
||||
|
||||
|
|
@ -313,9 +313,9 @@ Files:
|
|||
## Verification
|
||||
|
||||
```bash
|
||||
cargo test -p codebase-chat-core masquerade
|
||||
cargo test -p codebase-chat-relay masquerade
|
||||
cargo test -p codebase-chat-relay moderation_authz
|
||||
cargo test -p meridian-core masquerade
|
||||
cargo test -p meridian-relay masquerade
|
||||
cargo test -p meridian-relay moderation_authz
|
||||
just test
|
||||
just desktop-test
|
||||
just desktop-e2e-smoke
|
||||
|
|
@ -327,7 +327,7 @@ Confirm moderation never resolves through the display name — this is the
|
|||
security-relevant invariant:
|
||||
|
||||
```bash
|
||||
grep -rn "masquerade" crates/codebase-chat-relay/src/handlers/moderation_authz.rs
|
||||
grep -rn "masquerade" crates/meridian-relay/src/handlers/moderation_authz.rs
|
||||
```
|
||||
|
||||
Any hit outside a test module means authorization is reading display identity.
|
||||
|
|
|
|||
|
|
@ -6,14 +6,14 @@
|
|||
>
|
||||
> **Tracked in:** `.beads` — epic `codebaseChat-parity`
|
||||
|
||||
# Parity Index: Stoat Chat → Codebase Chat
|
||||
# Parity Index: Stoat Chat → Meridian
|
||||
|
||||
What the reference implementation has that Codebase Chat does not, why each gap
|
||||
What the reference implementation has that Meridian does not, why each gap
|
||||
matters, and — equally important — **what was examined and found not to be a
|
||||
gap**.
|
||||
|
||||
Scope was deliberately narrowed to *confirmed* gaps. A reference feature was
|
||||
excluded when Codebase Chat has a working equivalent, even a differently-shaped
|
||||
excluded when Meridian has a working equivalent, even a differently-shaped
|
||||
one. The exclusion table below is the evidence that the eight included specs are
|
||||
a considered subset rather than wherever the survey happened to stop.
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ against the current three-role model would mean specifying them twice.
|
|||
|
||||
## Three orphaned kinds
|
||||
|
||||
The survey's most reusable finding. Codebase Chat has a recurring failure mode:
|
||||
The survey's most reusable finding. Meridian has a recurring failure mode:
|
||||
an event kind is declared in `kind.rs`, registered in `ALL_KINDS`, sometimes
|
||||
range-matched by the relay, and then read and written by nothing.
|
||||
|
||||
|
|
@ -71,23 +71,23 @@ in a diff and is indistinguishable from nothing at runtime.
|
|||
|
||||
## Examined and excluded
|
||||
|
||||
Reference features that are **not** gaps. Each has a working Codebase Chat
|
||||
Reference features that are **not** gaps. Each has a working Meridian
|
||||
equivalent; the shape often differs.
|
||||
|
||||
| Reference feature | Codebase Chat equivalent | Verdict |
|
||||
| Reference feature | Meridian equivalent | Verdict |
|
||||
| --- | --- | --- |
|
||||
| Custom emoji (`routes/customisation`) | `desktop/src/features/custom-emoji/`, kinds 10030/30030 | present |
|
||||
| Voice channels (LiveKit, `voice_join.rs`) | `features/huddle/`, relay-hosted audio | present, different model |
|
||||
| Server audit log (`audit_log_query.rs`) | `codebase-chat-audit` hash-chain — **stronger**; reference has a bit, this has a subsystem | present |
|
||||
| Server audit log (`audit_log_query.rs`) | `meridian-audit` hash-chain — **stronger**; reference has a bit, this has a subsystem | present |
|
||||
| Bans / kicks / timeouts | kinds 9040–9044, `moderation_authz.rs` | present |
|
||||
| Safety reports (`safety/report_content.rs`) | `KIND_REPORT` 1984, `features/moderation/` | present |
|
||||
| Invites (`routes/invites`) | kind 9009, `mobile/lib/features/invites/`, `api/invites.rs` | present |
|
||||
| Group DMs (`group_create.rs`) | kinds 41010–41012, 41001 | present |
|
||||
| Message pins (`message_pin.rs`) | kind 40004 | present |
|
||||
| Message search (`message_search.rs`) | `codebase-chat-search`, Postgres FTS, NIP-50 | present |
|
||||
| Message search (`message_search.rs`) | `meridian-search`, Postgres FTS, NIP-50 | present |
|
||||
| Read state / acks (`channel_ack.rs`) | `KIND_READ_STATE` 30078 | present |
|
||||
| File uploads (`services/autumn`) | `codebase-chat-media`, Blossom/S3 | present |
|
||||
| Push notifications (`daemons/pushd`) | `codebase-chat-push-gateway`, `KIND_PUSH_LEASE` | present |
|
||||
| File uploads (`services/autumn`) | `meridian-media`, Blossom/S3 | present |
|
||||
| Push notifications (`daemons/pushd`) | `meridian-push-gateway`, `KIND_PUSH_LEASE` | present |
|
||||
| Webhooks (`routes/webhooks`) | `/hooks/{id}`, `api/bridge.rs:1817` | present, workflow-scoped |
|
||||
| User settings sync (`routes/sync`) | `features/settings/`, relay-persisted | present |
|
||||
| Onboarding (`routes/onboard`) | `features/onboarding/` | present |
|
||||
|
|
@ -95,7 +95,7 @@ equivalent; the shape often differs.
|
|||
| Typing indicators | kind 20002 | present |
|
||||
| Reactions (`message_react.rs`) | kind 7 | present |
|
||||
| Sessions (`routes/session`) | Nostr keypair + NIP-42; no password sessions to manage | n/a by design |
|
||||
| MFA / TOTP (`routes/mfa`) | key-based auth; NIP-AB device pairing (`codebase-chat-pair-relay`) | n/a by design |
|
||||
| MFA / TOTP (`routes/mfa`) | key-based auth; NIP-AB device pairing (`meridian-pair-relay`) | n/a by design |
|
||||
| Account email/password (`routes/account`) | no passwords exist | n/a by design |
|
||||
| Friend requests (`add_friend.rs`, `find_mutual.rs`) | `KIND_CONTACT_LIST` (kind 3) follow graph | different product concept — see [blocking](./feature-user-blocking.md) Current State |
|
||||
| GIF search (`services/gifbox`, Tenor proxy) | none | genuine gap, **deliberately excluded** — a third-party API integration, not architecture |
|
||||
|
|
@ -116,7 +116,7 @@ silent.
|
|||
|
||||
## What the reference does not have
|
||||
|
||||
Direction matters when reading these specs. Codebase Chat leads in areas with no
|
||||
Direction matters when reading these specs. Meridian leads in areas with no
|
||||
reference counterpart at all, and several parity items must be built *without
|
||||
regressing* them:
|
||||
|
||||
|
|
@ -126,7 +126,7 @@ regressing* them:
|
|||
Identity gaps here (nicknames, masquerade) are *harder* to solve because the
|
||||
reference's answer is "mutable server row".
|
||||
- **Audit hash-chain** — `ViewAuditLogs` is one permission bit there.
|
||||
- **Workflows** — `codebase-chat-workflow`, YAML-as-code. No counterpart.
|
||||
- **Workflows** — `meridian-workflow`, YAML-as-code. No counterpart.
|
||||
- **Projects / NIP-34 git** — no counterpart.
|
||||
- **Mesh compute, huddle audio, canvas, pulse** — no counterparts.
|
||||
|
||||
|
|
@ -140,7 +140,7 @@ Two specs turn this into a design constraint rather than a footnote:
|
|||
`Keybinds` store is a **hollow shell** — `TypeKeybinds = { _phantom?: never }`,
|
||||
`default()` returns `{}`, defaults commented out. Its `DEFAULT_SEQUENCES` also
|
||||
binds `NAVIGATION_CHANNEL_UP` and `_DOWN` to the same chord, making channel-up
|
||||
unreachable on non-Mac. Codebase Chat's 27-entry table is more complete and
|
||||
unreachable on non-Mac. Meridian's 27-entry table is more complete and
|
||||
more correct.
|
||||
|
||||
**The reference is a source of evidence, not a specification.** Where it is
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ would shadow it.
|
|||
3. A payer attests settlement (kind 50402, carrying the txid); any observer
|
||||
can verify the claim against the chain with their own RPC, and clients
|
||||
render **claimed** and **verified** as visibly distinct states.
|
||||
4. Agents can do all of the above through `codebase-chat payments …` with JSON
|
||||
4. Agents can do all of the above through `meridian payments …` with JSON
|
||||
output and the documented exit codes.
|
||||
5. An agent can buy an x402-protected HTTP resource (`exact` scheme, EVM)
|
||||
under a hard local spend cap.
|
||||
|
|
@ -119,7 +119,7 @@ would shadow it.
|
|||
web; Phase 0.3 scopes that non-goal's wording so it stops shadowing this
|
||||
feature.
|
||||
- **No workflow `send_payment` action yet.** Only `CallWebhook` is retry-safe
|
||||
(`crates/codebase-chat-workflow/src/schema.rs:222-235`); a payment action is
|
||||
(`crates/meridian-workflow/src/schema.rs:222-235`); a payment action is
|
||||
the least idempotent action conceivable and waits for the idempotency-key
|
||||
design that comment names as missing. When it lands it joins the
|
||||
elevated-authority set (`schema.rs:238-257`).
|
||||
|
|
@ -135,13 +135,13 @@ implementation. All "zap" hits are the lucide icon; all "wallet" hits are OS
|
|||
keyrings (`SECURITY.md:80`).
|
||||
|
||||
**The relay already advertises a payment slot, hardcoded off.**
|
||||
`crates/codebase-chat-relay/src/nip11.rs:127-128` declares
|
||||
`crates/meridian-relay/src/nip11.rs:127-128` declares
|
||||
`payment_required: bool`; `:159` pins it `false`. `RelayInfo` has
|
||||
`supported_extensions: Option<Vec<String>>` (`nip11.rs:73-92`) — the natural
|
||||
place to advertise `"x402"` without touching `supported_nips`.
|
||||
|
||||
**The repo's only 402 handling is buyer-side already:**
|
||||
`crates/codebase-chat-agent/src/llm.rs:6017` maps `402 => "402 Payment
|
||||
`crates/meridian-agent/src/llm.rs:6017` maps `402 => "402 Payment
|
||||
Required"` from upstream LLM providers.
|
||||
|
||||
**The record says payments are rejected.** `docs/nostr-nip-support-matrix.md`
|
||||
|
|
@ -154,10 +154,10 @@ enough to cover this feature).
|
|||
|
||||
| Seam | Where |
|
||||
| --- | --- |
|
||||
| Kind registry + closed ingest allowlist | `crates/codebase-chat-core/src/kind.rs` (`ALL_KINDS` :580); `required_scope_for_kind` at `crates/codebase-chat-relay/src/handlers/ingest.rs:211` — an unlisted kind is rejected `restricted: unknown event kind` (the NIP-17/10050 lesson) |
|
||||
| Kind registry + closed ingest allowlist | `crates/meridian-core/src/kind.rs` (`ALL_KINDS` :580); `required_scope_for_kind` at `crates/meridian-relay/src/handlers/ingest.rs:211` — an unlisted kind is rejected `restricted: unknown event kind` (the NIP-17/10050 lesson) |
|
||||
| Envelope validators | `ingest.rs:985` (engram), `:1054` (persona), `:1298` (reminder) — the pattern for `validate_payment_envelope` |
|
||||
| Kind-reader gate | `just check-kinds` (`scripts/check-kind-readers.mjs`); the CLI is inside the `crates` scan root, so a CLI reader satisfies it |
|
||||
| SDK builders | `crates/codebase-chat-sdk/src/builders.rs` |
|
||||
| SDK builders | `crates/meridian-sdk/src/builders.rs` |
|
||||
| CLI group pattern | `commands/mod.rs` + `Cmd` enum (`lib.rs:178-243`) + dispatch (`lib.rs:1842-1862`) + `commands/workflows.rs` as the model; stderr-caveat idiom at `commands/workflows.rs:77-79` |
|
||||
| x402 seller seams (deferred) | global layer next to `track_metrics` (`router.rs:201`), per-sub-router layer (`media_router`, `router.rs:46`), or `api_error(StatusCode, msg)` per-route (`api/mod.rs:26`) |
|
||||
| Desktop kind mirror | `desktop/src/shared/constants/kinds.ts` (bare numbers; timeline set `CHANNEL_TIMELINE_CONTENT_KINDS` :135) |
|
||||
|
|
@ -227,7 +227,7 @@ cross-reference this spec.
|
|||
### Phase 1 — Vocabulary + CLI (closes P1)
|
||||
|
||||
**Task 1.1: Failing tests for the payment grammar.**
|
||||
Create `crates/codebase-chat-core/src/payment.rs`, register in `lib.rs`:
|
||||
Create `crates/meridian-core/src/payment.rs`, register in `lib.rs`:
|
||||
|
||||
```rust
|
||||
#[test]
|
||||
|
|
@ -253,9 +253,9 @@ fn attestation_dedupe_key_is_network_and_tx() {
|
|||
}
|
||||
```
|
||||
|
||||
`cargo test -p codebase-chat-core payment` — FAIL, implement, PASS.
|
||||
`cargo test -p meridian-core payment` — FAIL, implement, PASS.
|
||||
|
||||
**Task 1.2: Kinds.** `crates/codebase-chat-core/src/kind.rs`: constants with
|
||||
**Task 1.2: Kinds.** `crates/meridian-core/src/kind.rs`: constants with
|
||||
`/// NIP-CP:` doc comments, a `// Payments (50400–50499)` group header,
|
||||
`ALL_KINDS` entries, and range assertions:
|
||||
|
||||
|
|
@ -271,19 +271,19 @@ KIND_PAYMENT_ATTESTATION => Scope::MessagesWrite` (the workflow :321 pattern)
|
|||
plus `validate_payment_envelope` (required tags, CAIP-2 shape, amount and
|
||||
txid format, sane expiration; **no chain calls**). Failing ingest test first.
|
||||
|
||||
**Task 1.4: SDK builders.** `crates/codebase-chat-sdk/src/builders.rs`:
|
||||
**Task 1.4: SDK builders.** `crates/meridian-sdk/src/builders.rs`:
|
||||
`build_payment_endpoints`, `build_payment_request`, `build_payment_attestation`.
|
||||
|
||||
**Task 1.5: CLI group** (the reader that satisfies `check-kinds`). New
|
||||
`crates/codebase-chat-cli/src/commands/payments.rs`, `pub mod payments;`,
|
||||
`crates/meridian-cli/src/commands/payments.rs`, `pub mod payments;`,
|
||||
`Payments(PaymentsCmd)` in `Cmd`, dispatch line at `lib.rs:1842-1862`:
|
||||
|
||||
```
|
||||
codebase-chat payments endpoints-set --addr eip155:8453=0x… [--addr kaspa:mainnet=kaspa:…]
|
||||
codebase-chat payments endpoints --user <pubkey>
|
||||
codebase-chat payments request --channel <uuid> --network <caip2> --asset <caip19|native> --amount <atomic> [--payer <pubkey>] [--expires <unix>]
|
||||
codebase-chat payments attest --channel <uuid> --to <pubkey> --tx <txid> --network … --asset … --amount … [--request <event-id>]
|
||||
codebase-chat payments list --channel <uuid> # explicit kinds filter — p-gate
|
||||
meridian payments endpoints-set --addr eip155:8453=0x… [--addr kaspa:mainnet=kaspa:…]
|
||||
meridian payments endpoints --user <pubkey>
|
||||
meridian payments request --channel <uuid> --network <caip2> --asset <caip19|native> --amount <atomic> [--payer <pubkey>] [--expires <unix>]
|
||||
meridian payments attest --channel <uuid> --to <pubkey> --tx <txid> --network … --asset … --amount … [--request <event-id>]
|
||||
meridian payments list --channel <uuid> # explicit kinds filter — p-gate
|
||||
```
|
||||
|
||||
Conventions: JSON stdout, warnings to stderr — `list` emits the
|
||||
|
|
@ -292,7 +292,7 @@ before treating one as settled."* Exit 5 on 10402 LWW conflict, documented in
|
|||
`lib.rs:76`.
|
||||
|
||||
**Task 1.6: Integration test.**
|
||||
`crates/codebase-chat-test-client/tests/e2e_payments.rs` (`just test`):
|
||||
`crates/meridian-test-client/tests/e2e_payments.rs` (`just test`):
|
||||
endpoints round-trip; request accepted in-channel and rejected cross-channel
|
||||
(h-scope); attestation with malformed txid rejected by the envelope validator;
|
||||
attestation readable by channel members.
|
||||
|
|
@ -304,7 +304,7 @@ against a mocked RPC first. Ethereum: `eth_getTransactionReceipt` — status 1,
|
|||
`to`/`value` for native, or an ERC-20 `Transfer` log matching
|
||||
`(contract, to, amount)`. Kaspa: REST (`api.kaspa.org`-compatible, URL
|
||||
configurable) — outputs contain `(address, amount)`. Config:
|
||||
`CODEBASE_CHAT_ETH_RPC_URL`, `CODEBASE_CHAT_KASPA_API_URL`, confirmation
|
||||
`MERIDIAN_ETH_RPC_URL`, `MERIDIAN_KASPA_API_URL`, confirmation
|
||||
threshold flag.
|
||||
|
||||
**Task 2.2: Fail stale, never wrong.** RPC unreachable → exit 2 with
|
||||
|
|
@ -334,13 +334,13 @@ address in the signed request they can see.
|
|||
|
||||
### Phase 4 — x402 buyer (closes P5)
|
||||
|
||||
**Task 4.1:** `codebase-chat x402 get --url <url> --max-amount <atomic>
|
||||
**Task 4.1:** `meridian x402 get --url <url> --max-amount <atomic>
|
||||
[--network <caip2>]`. Failing test against a local mock 402 server first.
|
||||
Flow: request → parse `accepts` (v1 + v2 shapes) → select `exact`/EVM
|
||||
requirement within the cap → sign EIP-3009 `transferWithAuthorization`
|
||||
(EIP-712, `alloy` crates) → retry with `X-PAYMENT` → surface
|
||||
`X-PAYMENT-RESPONSE` (settlement tx) in JSON output. Key:
|
||||
`CODEBASE_CHAT_X402_EVM_KEY` (client env only). **The cap check precedes
|
||||
`MERIDIAN_X402_EVM_KEY` (client env only). **The cap check precedes
|
||||
signing** — a signed authorization is spent authority even if the request
|
||||
aborts. Optionally publish a 50402 attestation when the seller is a community
|
||||
member (`--attest --channel …`).
|
||||
|
|
@ -373,7 +373,7 @@ Against [`feature-preview-graduation.md`](./feature-preview-graduation.md):
|
|||
## Verification
|
||||
|
||||
```bash
|
||||
cargo test -p codebase-chat-core payment
|
||||
cargo test -p meridian-core payment
|
||||
just check-kinds # kinds have readers, no allowlist growth
|
||||
just test # e2e_payments.rs; needs Postgres + Dragonfly
|
||||
just desktop-test
|
||||
|
|
@ -384,7 +384,7 @@ Confirm the kinds are not orphaned and custody never crept in:
|
|||
|
||||
```bash
|
||||
grep -rn "KIND_PAYMENT" crates desktop/src | grep -v kind.rs | head
|
||||
git grep -inE "private.?key|secret.?key" crates/codebase-chat-relay/src | grep -i "eth\|evm\|kaspa\|x402" # → no output
|
||||
git grep -inE "private.?key|secret.?key" crates/meridian-relay/src | grep -i "eth\|evm\|kaspa\|x402" # → no output
|
||||
```
|
||||
|
||||
Confirm the record was amended before code (Phase 0):
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
# Feature: Portable Deployment Profiles
|
||||
|
||||
Codebase Chat needs a go-to-market path that does not guess the final hosting
|
||||
Meridian needs a go-to-market path that does not guess the final hosting
|
||||
provider. The deployable product is therefore the published relay image plus its
|
||||
PostgreSQL, Redis-protocol, S3-compatible, health, metrics, migration, identity,
|
||||
and recovery contracts. Docker Compose, Dokploy, Helm/Kubernetes, and selected
|
||||
|
|
@ -46,7 +46,7 @@ can see them.
|
|||
|
||||
## Goals
|
||||
|
||||
1. Let an evaluator discover and deploy Codebase Chat from Dokploy with one
|
||||
1. Let an evaluator discover and deploy Meridian from Dokploy with one
|
||||
domain, generated stable secrets, a pinned relay image, and an honest
|
||||
evaluation warning.
|
||||
2. Let an operator use the same image and environment contract under bare
|
||||
|
|
@ -70,8 +70,8 @@ can see them.
|
|||
- Treating Docker Swarm replicas as HA while PostgreSQL, Redis, or MinIO remain
|
||||
single-node named volumes.
|
||||
- Treating Dokploy's own control-plane backup, a database dump, or a volume copy
|
||||
as a Codebase Chat consistency-set restore proof.
|
||||
- Executing `curl -sSL https://dokploy.com/install.sh | bash` from Codebase Chat
|
||||
as a Meridian consistency-set restore proof.
|
||||
- Executing `curl -sSL https://dokploy.com/install.sh | bash` from Meridian
|
||||
automation. Installation is an explicit operator action; record and verify
|
||||
the installed Dokploy version before qualification.
|
||||
- Adding the hosted-community control plane or push gateway to the first relay
|
||||
|
|
@ -88,15 +88,15 @@ can see them.
|
|||
| TLS bundle | `deploy/compose/compose.caddy.yml` and `deploy/compose/Caddyfile` put Caddy in front of the relay | Dokploy must use Traefik instead of starting a second public TLS owner |
|
||||
| External-state limitation | `deploy/compose/README.md:39-45` says the bundle fixes object storage to MinIO and requires a custom Compose file for external S3 | A reusable external-state Compose/Stack profile is missing |
|
||||
| Recovery | `deploy/compose/README.md:47-60` and `scripts/verify-backup-restore.sh` define an application-aware recovery set and isolated restore proof | Platform backup buttons are supplementary, never acceptance evidence |
|
||||
| HA contract | `deploy/charts/codebase-chat/README.md:164-188` requires Redis, subscriber-aware readiness, and per-replica Git scratch; `values.yaml` defines autoscaling | Swarm must preserve these invariants rather than merely setting `replicas` |
|
||||
| Object-store admission | `docs/git-on-object-storage.md` defines the A1-A3 contract; `crates/codebase-chat-relay/src/main.rs` makes its concurrent CAS probe startup-fatal | R2 is plausible but unqualified until the exact deployment passes the probe |
|
||||
| HA contract | `deploy/charts/meridian/README.md:164-188` requires Redis, subscriber-aware readiness, and per-replica Git scratch; `values.yaml` defines autoscaling | Swarm must preserve these invariants rather than merely setting `replicas` |
|
||||
| Object-store admission | `docs/git-on-object-storage.md` defines the A1-A3 contract; `crates/meridian-relay/src/main.rs` makes its concurrent CAS probe startup-fatal | R2 is plausible but unqualified until the exact deployment passes the probe |
|
||||
| Dokploy adapter | No `deploy/dokploy/`, Dokploy template, Dokploy contract test, or Dokploy guide exists; the existing relay host mapping uses `3000`, which conflicts with the default Dokploy panel port | The product is deployable manually, but the current bundle cannot be imported unchanged or supportably distributed through Dokploy |
|
||||
| Cloudflare adapter | No committed R2 example, Tunnel/LB origin policy, Worker, or Container adapter exists | Cloudflare remains an operator experiment rather than a named profile |
|
||||
|
||||
## External Capability Evidence
|
||||
|
||||
Re-check these before implementation; they describe third-party behavior as of
|
||||
2026-08-02, not a contract Codebase Chat controls.
|
||||
2026-08-02, not a contract Meridian controls.
|
||||
|
||||
| Capability | Current evidence | Design implication |
|
||||
| --- | --- | --- |
|
||||
|
|
@ -130,7 +130,7 @@ Binding requirements:
|
|||
remains authoritative.
|
||||
- WebSocket upgrades and long-lived connections pass end-to-end.
|
||||
- Direct origin access is denied before
|
||||
`CODEBASE_CHAT_MEDIA_UPLOAD_IP_HEADER=cf-connecting-ip` is enabled. The edge
|
||||
`MERIDIAN_MEDIA_UPLOAD_IP_HEADER=cf-connecting-ip` is enabled. The edge
|
||||
must strip inbound copies and set its own value.
|
||||
- HA relay replicas share one PostgreSQL authority, one supported Redis-protocol
|
||||
authority/fan-out plane, one S3-compatible object namespace, the same relay
|
||||
|
|
@ -161,7 +161,7 @@ dependencies. This spec does not imply that any implementation slice is done.
|
|||
| --- | --- | --- | --- |
|
||||
| PDP1 | No canonical deployment-profile matrix or parity test | Compose and Helm document similar contracts independently | P1 |
|
||||
| PDP2 | Existing public port/TLS ownership conflicts with Dokploy | `deploy/compose/compose.yml:23-24` binds host `3000`; Caddy owns `80/443`; Dokploy uses its panel and Traefik on those ports | P1 |
|
||||
| PDP3 | No upstream one-click Dokploy template | Codebase Chat absent from `Dokploy/templates` | P2 |
|
||||
| PDP3 | No upstream one-click Dokploy template | Meridian absent from `Dokploy/templates` | P2 |
|
||||
| PDP4 | External S3 is not configurable in the production Compose bundle | `deploy/compose/README.md:41-45` | P1 |
|
||||
| PDP5 | R2 conditional-write and recovery behavior is not live-qualified | No R2 evidence artifact exists; startup probe has not been run there | P1 |
|
||||
| PDP6 | Swarm replica/migration/state/rollback contracts are unspecified | Helm has HA guards; no Stack file or tests exist | P1 before any HA claim |
|
||||
|
|
@ -271,7 +271,7 @@ docker compose -f deploy/dokploy/compose.yml config
|
|||
bash scripts/test-dokploy-contract.sh
|
||||
bash scripts/test-deployment-profile-parity.sh
|
||||
bash scripts/test-verify-backup-restore.sh
|
||||
helm unittest deploy/charts/codebase-chat
|
||||
helm unittest deploy/charts/meridian
|
||||
just ci
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -301,7 +301,7 @@ This is the checklist every per-feature spec closes against.
|
|||
|
||||
1. **Protocol complete** — every event kind the relay accepts for this feature
|
||||
has a client implementation, or the unused kind is deleted from
|
||||
`codebase-chat-core/src/kind.rs`. A kind the relay validates and no client
|
||||
`meridian-core/src/kind.rs`. A kind the relay validates and no client
|
||||
ever sends is not a feature, it is a liability.
|
||||
2. **Protocol written down** — every kind the feature ships has a normative
|
||||
document **in `docs/nips/`**, and that document is listed in the `nips/`
|
||||
|
|
@ -314,7 +314,7 @@ This is the checklist every per-feature spec closes against.
|
|||
|
||||
- **A spec off the documented path is indistinguishable from a missing one.**
|
||||
NIP-AB shipped complete — 824 normative lines and a Tamarin model — from
|
||||
`crates/codebase-chat-core/src/pairing/`, where the index never pointed and every
|
||||
`crates/meridian-core/src/pairing/`, where the index never pointed and every
|
||||
kind-vs-spec audit reported `kind:24134` as unspecified. Now at
|
||||
`docs/nips/NIP-AB.md`.
|
||||
- **A kind can hide inside a family that has a NIP.** `30176` (teams) sits
|
||||
|
|
@ -326,7 +326,7 @@ This is the checklist every per-feature spec closes against.
|
|||
`.settings/reference-code/nips/AGENTS.md` § Verification.
|
||||
3. **Advertisement is honest** — if the feature depends on a NIP being reachable
|
||||
by third parties, that NIP is in `SUPPORTED_NIPS`
|
||||
(`crates/codebase-chat-relay/src/nip11.rs`) **and** its carrier kinds are admitted
|
||||
(`crates/meridian-relay/src/nip11.rs`) **and** its carrier kinds are admitted
|
||||
by `required_scope_for_kind`. The ingest allowlist is closed, so a NIP that is
|
||||
advertised but unadmitted turns a client feature-check into a silent runtime
|
||||
failure — strictly worse than not advertising it. NIP-17 sat in this state
|
||||
|
|
@ -338,7 +338,7 @@ This is the checklist every per-feature spec closes against.
|
|||
renders. A surface shipping on a platform the manifest omits is a bug.
|
||||
5. **e2e coverage** — at least one spec in `desktop/tests/e2e/` exercises the
|
||||
primary flow, registered in `playwright.config.ts`.
|
||||
6. **Agent surface** — the capability is reachable from `codebase-chat-cli`, or
|
||||
6. **Agent surface** — the capability is reachable from `meridian-cli`, or
|
||||
the spec states why an agent has no business touching it.
|
||||
7. **Failure paths** — empty state, permission denial, and relay-offline each
|
||||
render something deliberate rather than a blank panel.
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@
|
|||
The `codebaseChat-ssx` real-repository QA lane is closed. Its five findings now
|
||||
have executable evidence and durable contracts:
|
||||
|
||||
- `NIP-GC` normatively defines the `codebase-chat-channel` ACL and the stable
|
||||
- `NIP-GC` normatively defines the `meridian-channel` ACL and the stable
|
||||
owner/repository coordinate.
|
||||
- host-scoped credential configuration resets inherited macOS keychain helpers,
|
||||
while the development environment rejects Git versions without `authtype`.
|
||||
|
|
@ -100,7 +100,7 @@ why its replacement test sweeps 52 of them. Screenshot the surface before
|
|||
declaring a register complete.
|
||||
|
||||
Projects was otherwise left untouched. Its remaining gaps are structural, and a
|
||||
refactor competing with the in-flight `buzz` → `codebase-chat` rename already in
|
||||
refactor competing with the in-flight `buzz` → `meridian` rename already in
|
||||
the working tree would produce conflicts for no user-visible gain.
|
||||
|
||||
Git repository browser and collaboration built on NIP-34. Protocol coverage is
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ Tabs (`pulse_page.dart:17`): `everyone`, `following`, `liked`, `agents`, `mine`.
|
|||
Tests: `mobile/test/features/pulse/note_card_test.dart`,
|
||||
`compose_note_page_test.dart`.
|
||||
|
||||
**CLI** — `crates/codebase-chat-cli/src/commands/notes.rs` (46K),
|
||||
**CLI** — `crates/meridian-cli/src/commands/notes.rs` (46K),
|
||||
`social.rs` (8.4K), `feed.rs` (2.6K), `reactions.rs`.
|
||||
|
||||
## Gap Register
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
# Feature: Rebindable Keyboard Shortcuts
|
||||
|
||||
Codebase Chat ships 26 keyboard shortcuts across four categories and a settings
|
||||
Meridian ships 26 keyboard shortcuts across four categories and a settings
|
||||
card that tells you what they are — and, since 2026-08-01, lets you search them.
|
||||
The card still says the rest in its own description: **"Shortcuts are
|
||||
read-only."**
|
||||
|
|
@ -20,7 +20,7 @@ this; a second reference — a local agentic coding tool surveyed 2026-08-01 —
|
|||
solves it thoroughly, and is now the exemplar for the *surface*. Keep them
|
||||
straight:
|
||||
|
||||
| | Revolt fork (`for-web`) | Agentic coding tool | Codebase Chat |
|
||||
| | Revolt fork (`for-web`) | Agentic coding tool | Meridian |
|
||||
| --- | --- | --- | --- |
|
||||
| Action indirection | ✅ `KeybindAction` enum | ✅ (implied by rebinding) | ❌ |
|
||||
| Conflict priority | ✅ `ACTION_PRIORITY` | not observable | ❌ |
|
||||
|
|
@ -34,7 +34,7 @@ straight:
|
|||
So the target is: take **structure** from the Revolt fork (action indirection,
|
||||
priority), take **surface** from the coding tool (search, per-binding edit,
|
||||
multi-binding, `Unassigned`), and add the persistence neither the Revolt fork
|
||||
nor Codebase Chat has.
|
||||
nor Meridian has.
|
||||
|
||||
The Revolt fork's `Keybinds` store is a hollow shell:
|
||||
|
||||
|
|
@ -72,7 +72,7 @@ standalone value, and it removes duplication that exists today.
|
|||
contains a copy-paste bug — `NAVIGATION_CHANNEL_UP` and
|
||||
`NAVIGATION_CHANNEL_DOWN` are both bound to `["Alt", "ArrowDown"]`
|
||||
(`keybindSequences.ts:7-8`), so channel-up is unreachable on non-Mac. The Mac
|
||||
table below it gets it right. Codebase Chat's existing 27-entry table is more
|
||||
table below it gets it right. Meridian's existing 27-entry table is more
|
||||
complete and more correct; keep it and add the action layer around it.
|
||||
|
||||
**Rejected: syncing keybinds via a Nostr kind.** Tempting for cross-device
|
||||
|
|
@ -108,7 +108,7 @@ proposed here.
|
|||
|
||||
## Current State
|
||||
|
||||
**Codebase Chat — 26 shortcuts, fully documented, searchable, entirely fixed.**
|
||||
**Meridian — 26 shortcuts, fully documented, searchable, entirely fixed.**
|
||||
|
||||
`desktop/src/shared/lib/keyboard-shortcuts.ts` exports a `KeyboardShortcut[]`
|
||||
with `id`, `label`, `description`, `keys`, `keysWindows`, `category`. Categories
|
||||
|
|
@ -137,7 +137,7 @@ desktop/src` returns 15 files including `app/AppShell.tsx`,
|
|||
— i.e. the table describes bindings that each handler implements independently.
|
||||
Nothing enforces that the documented key and the implemented key agree.
|
||||
|
||||
| Property | Codebase Chat | Reference |
|
||||
| Property | Meridian | Reference |
|
||||
| --- | --- | --- |
|
||||
| Shortcuts documented | 26, 4 categories | 12 actions |
|
||||
| Platform variants | `getPlatformKeys()` | two tables, one buggy |
|
||||
|
|
@ -265,7 +265,7 @@ Files:
|
|||
- Create: `desktop/src/features/settings/lib/keybindOverrides.test.mjs`
|
||||
|
||||
`localStorage`, keyed like `channelMutesStorage.ts` does
|
||||
(`codebase-chat-channel-mutes.v1` → `codebase-chat-keybinds.v1`). Not
|
||||
(`meridian-channel-mutes.v1` → `meridian-keybinds.v1`). Not
|
||||
community-scoped, so it must **not** go in `resetCommunityState()` — bindings
|
||||
survive a community switch. Note that explicitly in the file header; the
|
||||
default assumption in this codebase is the opposite.
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue