Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,7 @@ go.work.sum

# Serena
.serena/

# Local agent / planning artifacts (not for public commits)
.claude/
docs/superpowers/
41 changes: 40 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ generate:
make generate-go

generate-go:
rm -rf router/gen && buf generate --path proto/wg/cosmo/node --path proto/wg/cosmo/common --path proto/wg/cosmo/graphqlmetrics --template buf.router.go.gen.yaml
rm -rf router/gen && buf generate --path proto/wg/cosmo/node --path proto/wg/cosmo/common --path proto/wg/cosmo/graphqlmetrics --path proto/wg/cosmo/code_mode/yoko/v1 --template buf.router.go.gen.yaml
rm -rf graphqlmetrics/gen && buf generate --path proto/wg/cosmo/graphqlmetrics --path proto/wg/cosmo/common --template buf.graphqlmetrics.go.gen.yaml
rm -rf connect-go/wg && buf generate --path proto/wg/cosmo/platform --path proto/wg/cosmo/notifications --path proto/wg/cosmo/common --path proto/wg/cosmo/node --template buf.connect-go.go.gen.yaml

Expand Down Expand Up @@ -187,6 +187,45 @@ docker-build-minikube: docker-build-local
run-subgraphs-local:
cd demo && go run cmd/all/main.go

CODE_MODE_GOCACHE ?= /tmp/cosmo-code-mode-go-build-cache

.PHONY: code-mode-demo code-mode-demo-down code-mode-connect-demo code-mode-connect-demo-down

# Local Code Mode demo: small federation (employees, family, availability,
# mood) + Yoko mock + Cosmo Router with Code Mode and named operations.
# Router GraphQL on :3002, MCP on :5027. Full instructions, prerequisites
# (codex CLI on PATH), and tear-down: demo/code-mode/README.md.
code-mode-demo:
mkdir -p $(CODE_MODE_GOCACHE)
GOCACHE=$(CODE_MODE_GOCACHE) $(MAKE) -C router build
GOCACHE=$(CODE_MODE_GOCACHE) $(MAKE) -C demo/code-mode build-yoko
GOCACHE=$(CODE_MODE_GOCACHE) $(MAKE) -C demo/code-mode build-stdio-proxy
$(MAKE) -C demo/code-mode compose
./demo/code-mode/start.sh

# Tear down anything left behind by code-mode-demo.
code-mode-demo-down:
./demo/code-mode/start.sh --down

# Runs the code-mode router from source against the yoko Connect supergraph
# (plugins + composed config live in $(YOKO_DIR)). Uses different ports than
# code-mode-demo (router 3012, MCP 5037, yoko-mock 5038) so both can run at
# the same time. Set YOKO_DIR to your local yoko checkout, e.g.
# `make code-mode-connect-demo YOKO_DIR=/path/to/yoko`.
# Full instructions and prerequisites: demo/code-mode-connect/README.md.
YOKO_DIR ?=

code-mode-connect-demo:
@if [ -z "$(YOKO_DIR)" ]; then echo "YOKO_DIR is required (path to your yoko checkout). See demo/code-mode-connect/README.md" >&2; exit 1; fi
mkdir -p $(CODE_MODE_GOCACHE)
GOCACHE=$(CODE_MODE_GOCACHE) $(MAKE) -C router build
GOCACHE=$(CODE_MODE_GOCACHE) $(MAKE) -C demo/code-mode build-yoko
YOKO_DIR=$(YOKO_DIR) ./demo/code-mode-connect/start.sh

# Tear down anything left behind by code-mode-connect-demo.
code-mode-connect-demo-down:
./demo/code-mode-connect/start.sh --down

sync-go-workspace:
cd router && go mod tidy
cd demo && make bump-deps
Expand Down
56 changes: 56 additions & 0 deletions demo/code-mode-connect/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Code Mode Connect Demo

This demo runs the Code Mode router against an external `yoko` Connect supergraph instead of the local employees federation used by `make code-mode-demo`.
It is useful when you want to exercise Code Mode against a richer set of plugins (Pylon, Linear, PostHog, Circleback, Slack, Notion) served by the `yoko` project.

It is designed to coexist with `make code-mode-demo`: it uses different ports (router 3012, MCP 5037, yoko-mock 5038), so both demos can run side-by-side.

## Prerequisites

- A local checkout of the `yoko` Connect supergraph project (separate repository).
Inside that checkout you must already have built the plugins and composed the supergraph so that the directory contains:
- `config.json` — the composed router config for the yoko supergraph.
- `plugins/` — the plugin binaries the router will load.
- Go (toolchain matching the repo `go.mod`).
- The `codex` CLI on `PATH`, authenticated. The Yoko mock shells out to `codex` for query generation.

## Run

From the repository root, set `YOKO_DIR` to your local yoko checkout and run:

```sh
make code-mode-connect-demo YOKO_DIR=/path/to/yoko
```

`YOKO_DIR` is required.
The target fails fast with a clear error if it is missing or if the directory does not contain `config.json`.

What the target does:

1. Builds `router/router`.
2. Builds `demo/code-mode/yoko-mock/yoko-mock`.
3. Starts `yoko-mock` on `localhost:5038`.
4. Starts the router with `YOKO_DIR` as its working directory and `demo/code-mode-connect/router-config.yaml` as its config.
The router resolves `config.json` and `plugins/` relative to that CWD, which is why `YOKO_DIR` must be a real composed yoko checkout.

Expected ports:

- Router GraphQL: `http://localhost:3012/graphql`
- Code Mode MCP: `http://127.0.0.1:5037/mcp`
- Yoko mock: `http://localhost:5038`

## Tearing down

Press Ctrl-C in the foreground terminal.
If anything is left behind, run:

```sh
make code-mode-connect-demo-down
```

The process logs for background services are written to `/tmp/cosmo-code-mode-connect-demo-logs`.

## Auth headers

`router-config.yaml` propagates the auth headers expected by the yoko plugins (`X-Pylon-Token`, `X-Linear-Token`, `X-Posthog-Token`, `X-Circleback-Token`, `X-Slack-Token`, `X-Notion-Token`, etc.).
Provide values for these on the request side when calling the router so the plugins can reach their upstream services.
82 changes: 82 additions & 0 deletions demo/code-mode-connect/router-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
version: "1"

# Different ports than demo/code-mode/router-config.yaml so both demos can run
# side-by-side. See demo/code-mode-connect/start.sh for the matching yoko-mock
# port.
listen_addr: "localhost:3012"
graphql_path: "/graphql"
playground_enabled: false
json_log: false
log_level: info
dev_mode: true
router_registration: false

# These paths are resolved relative to the router's CWD. start.sh runs the
# router from inside the yoko project dir, so "config.json" and "plugins" are
# the composed supergraph and the plugin binaries that ship with that repo.
execution_config:
file:
path: "config.json"
watch: false

plugins:
enabled: true
path: "plugins"

# Header propagation for the yoko plugins. Mirrors yoko/config.yaml so the
# plugins receive the same auth headers when the code-mode router fronts them.
headers:
all:
request:
- op: propagate
named: X-Pylon-Token
- op: propagate
named: X-Linear-Token
- op: propagate
named: X-Linear-Auth-Scheme
- op: propagate
named: X-Posthog-Token
- op: propagate
named: X-Posthog-Host
- op: propagate
named: X-Posthog-Project-Id
- op: propagate
named: X-Circleback-Token
- op: propagate
named: X-Slack-Token
- op: propagate
named: X-Notion-Token

graphql_metrics:
enabled: false

telemetry:
tracing:
enabled: false
metrics:
otlp:
enabled: false
prometheus:
enabled: false

mcp:
enabled: false
graph_name: code-mode-connect-demo
router_url: http://localhost:3012/graphql
session:
stateless: false
code_mode:
enabled: true
server:
# IPv4-only bind, see demo/code-mode/router-config.yaml for the why.
listen_addr: 127.0.0.1:5037
require_mutation_approval: true
sandbox:
timeout: 180s
query_generation:
enabled: true
endpoint: http://localhost:5038
timeout: 180s
execute_timeout: 180s
named_ops:
enabled: true
146 changes: 146 additions & 0 deletions demo/code-mode-connect/start.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
#!/usr/bin/env bash

set -Eeuo pipefail

ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
DEMO_DIR="$ROOT_DIR/demo"
CONNECT_DIR="$DEMO_DIR/code-mode-connect"
PID_FILE="/tmp/cosmo-code-mode-connect-demo.pids"
LOG_DIR="/tmp/cosmo-code-mode-connect-demo-logs"
GOCACHE_DIR="${GOCACHE:-/tmp/cosmo-code-mode-go-build-cache}"

# Yoko project that owns the supergraph + plugin binaries. Required:
# YOKO_DIR=/path/to/yoko ./start.sh
YOKO_DIR="${YOKO_DIR:?YOKO_DIR is required (path to your yoko checkout)}"

ROUTER_BIN="$ROOT_DIR/router/router"
ROUTER_CONFIG="$CONNECT_DIR/router-config.yaml"
YOKO_BIN="$DEMO_DIR/code-mode/yoko-mock/yoko-mock"

append_pid() {
local name="$1"
local pid="$2"
printf '%s %s\n' "$name" "$pid" >> "$PID_FILE"
}

kill_pid_file() {
if [ ! -f "$PID_FILE" ]; then
echo "No code-mode-connect demo PID file found at $PID_FILE"
return 0
fi

while read -r name pid; do
[ -n "${pid:-}" ] || continue
if kill -0 "$pid" 2>/dev/null; then
echo "Stopping $name pid=$pid"
kill "$pid" 2>/dev/null || true
fi
done < "$PID_FILE"

sleep 1

while read -r name pid; do
[ -n "${pid:-}" ] || continue
if kill -0 "$pid" 2>/dev/null; then
echo "Force stopping $name pid=$pid"
kill -KILL "$pid" 2>/dev/null || true
fi
done < "$PID_FILE"

rm -f "$PID_FILE"
}

cleanup() {
local status=$?
trap - EXIT INT TERM
kill_pid_file
exit "$status"
}

wait_url() {
local name="$1"
local url="$2"
local timeout="${3:-90}"
local start
start="$(date +%s)"

while true; do
if curl -fsS "$url" >/dev/null 2>&1; then
echo "$name is ready at $url"
return 0
fi

if [ "$(( $(date +%s) - start ))" -ge "$timeout" ]; then
echo "Timed out waiting for $name at $url" >&2
echo "Logs are in $LOG_DIR" >&2
return 1
fi

sleep 1
done
}

start_background_root() {
local name="$1"
shift

echo "Starting $name"
# exec replaces the subshell with the binary, so $! is the binary's pid.
# Without exec, the subshell forks the binary and `--down` ends up signalling
# an already-exited subshell while the real process keeps running.
(
cd "$ROOT_DIR"
exec "$@"
) > "$LOG_DIR/$name.log" 2>&1 &
append_pid "$name" "$!"
}

if [ "${1:-}" = "--down" ]; then
kill_pid_file
exit 0
fi

if [ ! -d "$YOKO_DIR" ]; then
echo "Yoko project directory not found: $YOKO_DIR" >&2
echo "Set YOKO_DIR to override." >&2
exit 1
fi

if [ ! -x "$ROUTER_BIN" ]; then
echo "Router binary not found or not executable: $ROUTER_BIN" >&2
echo "Run: cd router && make build" >&2
exit 1
fi

if [ ! -x "$YOKO_BIN" ]; then
echo "Yoko mock binary not found or not executable: $YOKO_BIN" >&2
echo "Run: make -C demo/code-mode build-yoko" >&2
exit 1
fi

if [ ! -f "$YOKO_DIR/config.json" ]; then
echo "Composed yoko supergraph not found: $YOKO_DIR/config.json" >&2
echo "Run: cd $YOKO_DIR && make compose" >&2
exit 1
fi

mkdir -p "$LOG_DIR"
mkdir -p "$GOCACHE_DIR"
rm -f "$PID_FILE"
trap cleanup EXIT INT TERM

# yoko-mock listens on a different port than the regular code-mode-demo so the
# two demos can coexist (5028 vs 5038).
start_background_root yoko "$YOKO_BIN" -listen-addr localhost:5038

wait_url yoko http://localhost:5038/health

echo "Starting router in foreground (CWD=$YOKO_DIR)"
(
cd "$YOKO_DIR"
exec "$ROUTER_BIN" -config "$ROUTER_CONFIG"
) &
router_pid="$!"
append_pid router "$router_pid"

wait "$router_pid"
1 change: 1 addition & 0 deletions demo/code-mode/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mcp-stdio-proxy/mcp-stdio-proxy
30 changes: 30 additions & 0 deletions demo/code-mode/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
SHELL := bash
GOCACHE ?= /tmp/cosmo-code-mode-go-build-cache
wgc_env_arg = $(if $(wildcard ../cli/.env),--env-file ../cli/.env,)
wgc_router = pnpm dlx tsx $(wgc_env_arg) ../cli/src/index.ts router

.PHONY: build-yoko build-stdio-proxy compose start down run-subgraphs

build-yoko:
mkdir -p $(GOCACHE)
cd yoko-mock && GOCACHE=$(GOCACHE) go build -o yoko-mock .

build-stdio-proxy:
mkdir -p $(GOCACHE)
cd mcp-stdio-proxy && GOCACHE=$(GOCACHE) go build -o mcp-stdio-proxy .

compose:
cd .. && if [ -f ../cli/dist/src/index.js ]; then \
DISABLE_UPDATE_CHECK=true node ../cli/dist/src/index.js router compose -i ./code-mode/graph.yaml -o ./code-mode/config.json; \
else \
DISABLE_UPDATE_CHECK=true TMPDIR=/tmp $(wgc_router) compose -i ./code-mode/graph.yaml -o ./code-mode/config.json; \
fi

start:
./start.sh

down:
./start.sh --down

run-subgraphs:
./run_subgraphs_subset.sh
Loading
Loading