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
237 changes: 108 additions & 129 deletions .github/workflows/hourly-product-development.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Hourly product development
name: Product development dispatch

on:
workflow_dispatch:
Expand All @@ -8,10 +8,6 @@ on:
required: false
default: false
type: boolean
schedule:
# Offset from the PR steward at minute 17 so protected merge evidence settles.
- cron: "41 * * * *"

concurrency:
group: hourly-product-development-${{ github.repository }}
cancel-in-progress: false
Expand All @@ -25,13 +21,7 @@ env:
CORE_WORKFLOWS: '["ci","CodeQL"]'
OPENCODE_VERSION: "1.17.13"
OPENCODE_SHA256: 157afa289d1a8d9372de0ce19ac726119b937a1f6b201808d46f06e4e59bb348
OPENCODE_MODEL_CANDIDATES: >-
nvidia-nim/nvidia/llama-3.3-nemotron-super-49b-v1.5
nvidia-nim/nvidia/nemotron-3-super-120b-a12b
nvidia-nim/deepseek-ai/deepseek-v4-pro
OPENCODE_RUN_TIMEOUT_SECONDS: "2100"
NIM_PROXY_HOST: "127.0.0.1"
NIM_PROXY_PORT: "8765"
CONTEXTUAL_ORCHESTRATOR_POOL: free

jobs:
develop-product-gap:
Expand All @@ -55,11 +45,14 @@ jobs:
disable-telemetry: true
allowed-endpoints: >-
api.github.com:443
api.bytez.com:443
api.openai.com:443
cafe.github.com:443
codeload.github.com:443
github.com:443
integrate.api.nvidia.com:443
objects.githubusercontent.com:443
openrouter.ai:443
raw.githubusercontent.com:443
registry.npmjs.org:443
release-assets.githubusercontent.com:443
Expand Down Expand Up @@ -305,12 +298,22 @@ jobs:

- name: Check out the protected default branch without persisted credentials
if: steps.gate.outputs.develop == 'true'
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
ref: main
fetch-depth: 1
persist-credentials: false

- name: Check out immutable central automation source
if: steps.gate.outputs.develop == 'true'
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: ContextualWisdomLab/.github
ref: dcd35b7653854edb2ea26a87bac2035f12d8d903
fetch-depth: 1
persist-credentials: false
path: trusted-organization-source

- name: Set up Python
if: steps.gate.outputs.develop == 'true'
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
Expand Down Expand Up @@ -407,7 +410,7 @@ jobs:
or touch more than 12 files or 1,500 changed lines.
- Do not stage, commit, push, open or merge a pull request, approve work, tag,
or publish a release. This workspace contains no .git directory and the
model process receives no GitHub, OIDC, or upstream NVIDIA credential.
model process receives no GitHub, OIDC, or upstream provider credential.

Before finishing, run focused tests and the available local quality gates with
the preinstalled environment. Update CHANGELOG.md [Unreleased], beginner-
Expand All @@ -421,87 +424,76 @@ jobs:
required checks. Do not publish a release.
PROMPT

- name: Start the loopback-only NIM credential broker
- name: Provision the pinned contextual-orchestrator sidecar
if: steps.gate.outputs.develop == 'true'
id: nim_broker
id: orchestrator
shell: bash
env:
NIM_UPSTREAM_API_KEY: ${{ secrets.NVIDIA_NIM_API_KEY }}
BYTEZ_API_KEY: ${{ secrets.BYTEZ_API_KEY }}
NVIDIA_NIM_API_KEY: ${{ secrets.NVIDIA_NIM_API_KEY }}
NVIDIA_NIM_API_KEY_SUB: ${{ secrets.NVIDIA_NIM_API_KEY_SUB }}
OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: |
set -euo pipefail
if [ -z "${NIM_UPSTREAM_API_KEY:-}" ]; then
echo "::error::NVIDIA_NIM_API_KEY is required only for model-backed development."
exit 1
fi
secret_fingerprint="$(
python3 - <<'PY'
import base64
import hashlib
import os

secret = os.environ["NIM_UPSTREAM_API_KEY"].encode("utf-8")
representations = (
secret,
base64.b64encode(secret),
base64.urlsafe_b64encode(secret),
secret.hex().encode("ascii"),
)
print(",".join(
f"{len(value)}:{hashlib.sha256(value).hexdigest()}"
for value in representations
))
fingerprints = []
for secret_name in (
"BYTEZ_API_KEY",
"NVIDIA_NIM_API_KEY",
"NVIDIA_NIM_API_KEY_SUB",
"OPENROUTER_API_KEY",
"OPENAI_API_KEY",
):
secret = os.environ.get(secret_name, "").encode("utf-8")
if not secret:
continue
for value in (
secret,
base64.b64encode(secret),
base64.urlsafe_b64encode(secret),
secret.hex().encode("ascii"),
):
fingerprints.append(
f"{len(value)}:{hashlib.sha256(value).hexdigest()}"
)
print(",".join(fingerprints))
PY
)"
printf 'secret_fingerprint=%s\n' "$secret_fingerprint" >>"$GITHUB_OUTPUT"
umask 077
proxy_log="${RUNNER_TEMP}/keyverse-nim-proxy.log"
proxy_pid="${RUNNER_TEMP}/keyverse-nim-proxy.pid"
python scripts/ci/nim_proxy.py \
--host "$NIM_PROXY_HOST" \
--port "$NIM_PROXY_PORT" \
>"$proxy_log" 2>&1 &
printf '%s\n' "$!" >"$proxy_pid"
unset NIM_UPSTREAM_API_KEY

ready=false
for _attempt in $(seq 1 30); do
if curl -fsS \
"http://${NIM_PROXY_HOST}:${NIM_PROXY_PORT}/healthz" \
>/dev/null; then
ready=true
break
fi
sleep 1
done
if [ "$ready" != "true" ]; then
cat "$proxy_log" >&2
echo "::error::The loopback NIM credential broker did not become ready."
exit 1
fi
bash "$GITHUB_WORKSPACE/trusted-organization-source/scripts/ci/contextual_orchestrator_review_sidecar.sh"

- name: Run the NVIDIA NIM development agent in a disposable workspace
- name: Run OpenCode through contextual-orchestrator in a disposable workspace
if: steps.gate.outputs.develop == 'true'
id: agent
shell: bash
env:
MODEL: contextual-orchestrator/orchestrator/free
run: |
set -euo pipefail
trap 'sudo pkill -KILL -u 65532 >/dev/null 2>&1 || true' EXIT
prompt="$(cat "${RUNNER_TEMP}/keyverse-agent-prompt.md")"
successful_workspace=""
trusted_venv="${GITHUB_WORKSPACE}/services/account_unification/.venv"

for model in $OPENCODE_MODEL_CANDIDATES; do
sudo pkill -KILL -u 65532 >/dev/null 2>&1 || true
agent_workspace="${RUNNER_TEMP}/keyverse-agent"
agent_home="${RUNNER_TEMP}/keyverse-agent-home"
rm -rf "$agent_workspace" "$agent_home"
install -d -m 0750 "$agent_workspace" "$agent_home" "$agent_home/tmp"
git archive HEAD | tar -x -C "$agent_workspace"

cat >"${agent_workspace}/opencode.json" <<'CONFIG'
agent_workspace="${RUNNER_TEMP}/keyverse-agent"
agent_home="${RUNNER_TEMP}/keyverse-agent-home"
rm -rf "$agent_workspace" "$agent_home"
install -d -m 0750 "$agent_workspace" "$agent_home" "$agent_home/tmp"
git archive HEAD | tar -x -C "$agent_workspace"
install -m 0644 \
"$GITHUB_WORKSPACE/trusted-organization-source/scripts/ci/load_contextual_orchestrator_token.sh" \
"$agent_home/load_contextual_orchestrator_token.sh"

cat >"${agent_workspace}/opencode.json" <<'CONFIG'
{
"$schema": "https://opencode.ai/config.json",
"enabled_providers": ["nvidia-nim"],
"model": "contextual-orchestrator/orchestrator/free",
"small_model": "contextual-orchestrator/orchestrator/free",
"enabled_providers": ["contextual-orchestrator"],
"lsp": false,
"mcp": {},
"permission": {
Expand All @@ -518,90 +510,77 @@ jobs:
"external_directory": "deny"
},
"provider": {
"nvidia-nim": {
"contextual-orchestrator": {
"npm": "@ai-sdk/openai-compatible",
"name": "NVIDIA NIM through local Keyverse broker",
"name": "Contextual Orchestrator",
"options": {
"baseURL": "http://127.0.0.1:8765/v1",
"apiKey": "{env:NVIDIA_API_KEY}"
"baseURL": "{env:CONTEXTUAL_ORCHESTRATOR_BASE_URL}",
"apiKey": "{env:CONTEXTUAL_ORCHESTRATOR_TOKEN}"
},
"models": {
"nvidia/llama-3.3-nemotron-super-49b-v1.5": {
"name": "NVIDIA Llama 3.3 Nemotron Super 49B v1.5",
"tool_call": true,
"limit": {"context": 131072, "output": 8192}
},
"nvidia/nemotron-3-super-120b-a12b": {
"name": "NVIDIA Nemotron 3 Super 120B",
"tool_call": true,
"limit": {"context": 131072, "output": 8192}
},
"deepseek-ai/deepseek-v4-pro": {
"name": "DeepSeek V4 Pro (NIM)",
"orchestrator/free": {
"name": "Orchestrator Free",
"tool_call": true,
"limit": {"context": 131072, "output": 8192}
"reasoning": true,
"limit": {"context": 200000, "output": 32768}
}
}
}
}
}
CONFIG

sudo chown -R 65532:65532 "$agent_workspace" "$agent_home"
echo "::group::opencode $model"
if timeout --kill-after=30s "${OPENCODE_RUN_TIMEOUT_SECONDS}s" \
sudo -u '#65532' -g '#65532' env -i \
PATH="${trusted_venv}/bin:/usr/local/bin:/usr/bin:/bin" \
HOME="$agent_home" \
TMPDIR="$agent_home/tmp" \
PYTHONPATH="$agent_workspace/services/account_unification" \
PYTHONDONTWRITEBYTECODE=1 \
PIP_NO_INDEX=1 \
LANG=C.UTF-8 \
LC_ALL=C.UTF-8 \
NVIDIA_API_KEY=keyverse-local-broker \
OPENCODE_DISABLE_AUTOUPDATE=1 \
/bin/bash -c \
'ulimit -u 256; ulimit -n 1024; cd "$1"; exec opencode run "$2" --model "$3"' \
bash "$agent_workspace" "$prompt" "$model"; then
sudo pkill -KILL -u 65532 >/dev/null 2>&1 || true
successful_workspace="$agent_workspace"
echo "::endgroup::"
echo "Agent session completed with \`$model\`." >>"$GITHUB_STEP_SUMMARY"
break
fi
sudo pkill -KILL -u 65532 >/dev/null 2>&1 || true
echo "::endgroup::"
echo "::warning::Model $model failed; its disposable workspace was discarded."
done

if [ -z "$successful_workspace" ]; then
echo "::error::Every NVIDIA NIM model candidate failed."
if [ -z "${CONTEXTUAL_ORCHESTRATOR_BASE_URL:-}" ] || \
[ -z "${CONTEXTUAL_ORCHESTRATOR_TOKEN_FILE:-}" ]; then
echo "::error::The contextual-orchestrator sidecar did not export its connection files."
exit 1
fi
sudo chown -R "$(id -u):$(id -g)" "$successful_workspace"
rm -f "$successful_workspace/opencode.json"
echo "workspace=$successful_workspace" >>"$GITHUB_OUTPUT"
sudo chown -R 65532:65532 "$agent_workspace" "$agent_home"
sudo chown 65532:65532 "$CONTEXTUAL_ORCHESTRATOR_TOKEN_FILE"
sudo -u '#65532' -g '#65532' env -i \
PATH="${trusted_venv}/bin:/usr/local/bin:/usr/bin:/bin" \
HOME="$agent_home" \
TMPDIR="$agent_home/tmp" \
PYTHONPATH="$agent_workspace/services/account_unification" \
PYTHONDONTWRITEBYTECODE=1 \
PIP_NO_INDEX=1 \
LANG=C.UTF-8 \
LC_ALL=C.UTF-8 \
OPENCODE_DISABLE_AUTOUPDATE=1 \
MODEL="$MODEL" \
CONTEXTUAL_ORCHESTRATOR_BASE_URL="$CONTEXTUAL_ORCHESTRATOR_BASE_URL" \
CONTEXTUAL_ORCHESTRATOR_TOKEN_FILE="$CONTEXTUAL_ORCHESTRATOR_TOKEN_FILE" \
/bin/bash -c \
'set -euo pipefail; source "$HOME/load_contextual_orchestrator_token.sh"; ulimit -u 256; ulimit -n 1024; cd "$1"; exec opencode run "$2" --model "$MODEL"' \
bash "$agent_workspace" "$prompt"
sudo pkill -KILL -u 65532 >/dev/null 2>&1 || true
sudo chown -R "$(id -u):$(id -g)" "$agent_workspace"
rm -f "$agent_workspace/opencode.json"
echo "workspace=$agent_workspace" >>"$GITHUB_OUTPUT"

- name: Stop the credential broker and all model descendants
- name: Stop contextual-orchestrator and remove credential material
if: always() && steps.gate.outputs.develop == 'true'
shell: bash
run: |
set -euo pipefail
sudo pkill -KILL -u 65532 >/dev/null 2>&1 || true
proxy_pid_file="${RUNNER_TEMP}/keyverse-nim-proxy.pid"
if [ -s "$proxy_pid_file" ]; then
proxy_pid="$(cat "$proxy_pid_file")"
kill "$proxy_pid" >/dev/null 2>&1 || true
wait "$proxy_pid" >/dev/null 2>&1 || true
fi
sidecar_pattern="${RUNNER_TEMP}/contextual-orchestrator-review/launch_sidecar.py"
sanitizer_pattern="$GITHUB_WORKSPACE/trusted-organization-source/scripts/ci/sanitize_contextual_orchestrator_sidecar_stream.py"
pkill -KILL -f "$sidecar_pattern" >/dev/null 2>&1 || true
pkill -KILL -f "$sanitizer_pattern" >/dev/null 2>&1 || true
sudo rm -f -- "${CONTEXTUAL_ORCHESTRATOR_TOKEN_FILE:-/nonexistent}"
rm -rf -- \
"$GITHUB_WORKSPACE/trusted-organization-source" \
"$GITHUB_WORKSPACE/strix_runs" \
"$RUNNER_TEMP/contextual-orchestrator" \
"$RUNNER_TEMP/contextual-orchestrator-review"

- name: Capture the bounded credential-free patch
if: steps.gate.outputs.develop == 'true'
id: package
shell: bash
env:
KEYVERSE_FORBIDDEN_SECRET_FINGERPRINT: ${{ steps.nim_broker.outputs.secret_fingerprint }}
KEYVERSE_FORBIDDEN_SECRET_FINGERPRINT: ${{ steps.orchestrator.outputs.secret_fingerprint }}
run: |
set -euo pipefail
artifact_dir="${RUNNER_TEMP}/hourly-product-change"
Expand Down Expand Up @@ -882,7 +861,7 @@ jobs:
stream.write(body + "\n")
PY

branch="nim-agent/product-dev-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
branch="opencode-agent/product-dev-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
git config user.name "opencode-agent[bot]"
git config user.email "219766164+opencode-agent[bot]@users.noreply.github.com"
git config core.hooksPath /dev/null
Expand Down
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Keep a Changelog, and releases use semantic versioning.
- Authenticated, side-effect-free LDAP and Active Directory component preflight
with LDAPS-only transport, RFC 4514 distinguished-name validation, closed
read-only policy, bounded timeouts, and bind-secret redaction.
- An hourly fail-closed NVIDIA NIM OpenCode loop that isolates model credentials,
- A centrally dispatched fail-closed OpenCode loop using the immutable contextual-orchestrator `orchestrator/free` sidecar, isolating provider credentials,
requires a production-code/test/changelog vertical, independently verifies
the sealed patch, and opens one draft PR through a dedicated publication
token.
Expand Down
2 changes: 1 addition & 1 deletion docs/TRD.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ Readiness is component/lifecycle specific. Preflight success does not imply Keyc

## 12. Automation boundary

Autonomous development uses NVIDIA NIM/OpenCode through an isolated model phase. Model execution has no publication/reviewer/release authority. PR #74 is integrated in protected main; its operational boundary must still be proven by a protected-main scheduled or manual run.
Autonomous development uses OpenCode through the central contextual-orchestrator `orchestrator/free` sidecar in an isolated model phase. Model execution has no publication/reviewer/release authority. PR #74 is integrated in protected main; its operational boundary must still be proven by a protected-main centrally dispatched or manual run.

## 13. Change control

Expand Down
Loading
Loading