Skip to content
Draft
Show file tree
Hide file tree
Changes from 5 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