Skip to content
Draft
Show file tree
Hide file tree
Changes from 9 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/
44 changes: 43 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 --include-imports --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,48 @@ 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: federation of all non-EDFS demo subgraphs
# (employees, family, hobbies, products, test1, availability, mood, countries,
# plus the products_fg feature graph) + Cosmo Router with Code Mode and
# named operations. Router GraphQL on :3002, MCP on :5027. Yoko runs as a
# separate external service expected at http://127.0.0.1:3400 — start it
# before this target (override with YOKO_URL=...). Full instructions,
# prerequisites, 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-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 router/MCP
# ports than code-mode-demo (router 3012, MCP 5037) so both can run at the
# same time, and shares the same external yoko service expected at
# http://127.0.0.1:3400 (override with YOKO_URL=...). 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
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
6 changes: 6 additions & 0 deletions buf.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Generated by buf. DO NOT EDIT.
version: v2
deps:
- name: buf.build/bufbuild/protovalidate
commit: 50325440f8f24053b047484a6bf60b76
digest: b5:74cb6f5c0853c3c10aafc701614194bbd63326bdb8ef4068214454b8894b03ba4113e04b3a33a8321cdf05336e37db4dc14a5e2495db8462566914f36086ba31
2 changes: 2 additions & 0 deletions buf.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
version: v2
modules:
- path: proto
deps:
- buf.build/bufbuild/protovalidate
lint:
disallow_comment_ignores: true
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 router/MCP ports (router 3012, MCP 5037), and both demos share the same external Yoko service at `http://127.0.0.1:3400` (override with `YOKO_URL=...`).

## 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`).
- A running Yoko service reachable at `http://127.0.0.1:3400` (override with `YOKO_URL=...`).
The router calls Yoko for query generation; without it, `code_mode_search_tools` cannot generate operations.

## 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. Health-checks the external Yoko service at `$YOKO_URL/health` (default `http://127.0.0.1:3400`).
3. 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 (external): `http://127.0.0.1:3400`

## 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 router/MCP ports than demo/code-mode/router-config.yaml so both
# demos can run side-by-side. They share the same external yoko service
# (http://127.0.0.1:3400) — start.sh no longer launches a local yoko-mock.
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://127.0.0.1:3400
timeout: 180s
execute_timeout: 180s
named_ops:
enabled: true
159 changes: 159 additions & 0 deletions demo/code-mode-connect/start.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
#!/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 is a separate service expected at http://127.0.0.1:3400. start.sh no
# longer launches a local mock — bring up your real yoko service before running.
YOKO_URL="${YOKO_URL:-http://127.0.0.1:3400}"

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"
}

on_signal() {
trap - EXIT INT TERM
kill_pid_file
exit 0
}

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 [ ! -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
trap on_signal INT TERM

# Verify the external yoko service is reachable. We don't probe a specific
# path because the real service doesn't necessarily expose /health — just
# confirm the TCP/HTTP socket accepts a connection. Any HTTP response (200,
# 404, 405 …) means the server is up; only a connection failure aborts.
# Override with YOKO_URL when yoko runs at a different address.
if ! curl -sS -o /dev/null --max-time 3 "$YOKO_URL" >/dev/null 2>&1; then
echo "Yoko service is not reachable at $YOKO_URL" >&2
echo "Start your yoko service (or set YOKO_URL=...) before running this demo." >&2
exit 1
fi
echo "yoko is ready at $YOKO_URL"

echo "Starting router in foreground (CWD=$YOKO_DIR)"
echo "Router output is being teed to $LOG_DIR/router.log"
# Tee stdout+stderr so the user still sees live output AND we keep a persistent
# log for post-mortem debugging when the router exits unexpectedly.
(
cd "$YOKO_DIR"
exec "$ROUTER_BIN" -config "$ROUTER_CONFIG"
) 2>&1 | tee "$LOG_DIR/router.log" &
router_pid="$!"
append_pid router "$router_pid"

wait "$router_pid"
2 changes: 2 additions & 0 deletions demo/code-mode/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
mcp-stdio-proxy/mcp-stdio-proxy
schemas/
Loading
Loading