feat(harness): deployable Harness server + veadk harness CLI (create/add/show/deploy/invoke), with OAuth2/JWT deploy#603
Merged
Conversation
The Harness model now carries a `runtime` field (Literal["adk","codex"], default "adk") passed through to the Agent, so a deployed Harness server can run an agent on the codex runtime. Exposed on the CLI via `--runtime` on both `harness add` and `harness invoke` (one-time override). Docs + example updated.
… CLI - veadk/cloud/harness_app/: env-assembled agent + FastAPI harness server (/harness/invoke with clone-based once-time overrides; incremental, deduped tools/skills; per-invoke skill temp-dir cleanup) - veadk harness create/deploy/invoke; deploy builds the image via AgentKit and creates an AgentKit runtime (Name=HARNESS_NAME, tag "Harness") - invoke override flags are generated from HarnessOverrides - replaces the single-file veadk/cloud/harness_app.py
…eate/add/deploy - harness.yaml (layered, per-component) is the agent spec; env_mapping.to_runtime_env reuses veadk flatten_dict for generic fields and maps each component's backend connection params to the veadk DATABASE_* env vars the backend reads - veadk harness create/add/deploy: create scaffolds harness.yaml + .env.example (AK/SK only) + domestic-source Dockerfile; add edits harness.yaml; deploy builds the image on AgentKit cloud and creates a runtime via sdk.launch - runtime env names aligned (MODEL_NAME / KNOWLEDGE_BASE_TYPE / LONG_TERM_MEMORY_TYPE / SHORT_TERM_MEMORY_TYPE)
…ikey + invoke cmd; add --path takes a dir - create's harness.yaml now documents every component's supported backends and their connection params as comments (uncomment for your chosen type) - deploy surfaces the created runtime's id / endpoint / api key and a ready-to-run invoke command (from the deploy result's config_updates) - harness add --path now takes the harness directory (consistent with deploy); setting a component type preserves its existing connection params
…o harness.yaml
Lets users fill backend connection params from the CLI, e.g.
veadk harness add --long-term-memory-type viking \
--set long_term_memory.project=my-proj --set long_term_memory.region=cn-beijing
Values are parsed as YAML scalars (ints/bools stay typed); deploy maps them to
the veadk DATABASE_* env vars.
Replace the generic '--set KEY=VALUE' with explicit flags in the same style as '--short-term-memory-type', e.g. --long-term-memory-project, --short-term-memory-host. Flags are auto-generated from env_mapping.COMPONENT_BACKENDS so they stay in sync with the backends; values are written under the matching component section and mapped to the veadk DATABASE_* env vars on deploy.
…harness.yaml - add reuses invoke's HarnessOverrides-generated flags (--model-name/--tools/ --skills/--system-prompt/--runtime identical in both); --tools/--skills are comma-separated; --name (alias --harness-name) for the harness name; invoke also accepts --name - rename component knowledge_base -> knowledgebase (env KNOWLEDGEBASE_TYPE) - add writes connection params via explicit --<component>-<param> flags - add output: inline-style lists, and drop unset components (knowledgebase / long_term_memory); short_term_memory always shown - create's harness.yaml annotates each field with its env var + add flag - register demo tools (get_city_weather / get_location_weather) as built-ins
…rom it + --message
- deploy writes/updates ./harness.json: {name: {url, key, runtime_id}}
- invoke takes --name (reads url/key from harness.json), --message/-m (or positional);
--url/--key optional overrides; --path for harness.json location
…oy/invoke flow The reference still described the removed server-side `/harness/add` registration and the old `--harness/--url/--key` invoke design. Rewrite it around the current `veadk harness` flow: layered harness.yaml (knowledgebase/KNOWLEDGEBASE_TYPE), comma-separated --tools/--skills, per-component connection flags, deploy writing harness.json, and invoke resolving url/key by --name.
The contract tests still imported the removed `/harness/add` design (`AddHarnessRequest`/`AddHarnessResponse`/`Harness`/`_split_csv`), so the module failed to import. Rewrite against the current schemas: HarnessOverrides (per-call overridable) vs HarnessConfig (creation-time, with memory/kb), the InvokeHarness request/response models, and split_csv.
The server (harness_app) no longer exposes /harness/add — agents are assembled from env at deploy time, not registered at runtime — so the client 'add' command posted to a route that 404s. Remove it (and its contract tests); keep the working 'invoke' client and the shared _harness_request helper.
The example documented the removed /harness/add registration, the old `agentkit config --entry_point ...` deploy flow, and `python -m veadk.cloud.harness_app` (now a package, no __main__). Rewrite both READMEs around create -> add -> deploy -> invoke with harness.json, and drop the orphaned .env.example / requirements.txt (the scaffold is now generated by `veadk harness create`).
An `auth` block in harness.yaml (or --discovery-url / --allowed-id on deploy)
switches the runtime gateway to custom_jwt: it admits only JWTs issued by the
user pool at `discovery_url` whose audience is in `allowed_ids`. Absent an
`auth` block, deploy keeps the existing key_auth path unchanged.
The auth block is excluded from the flattened runtime env (it configures the
gateway authorizer, not the container). No secret is involved — the user pool /
client / external IdP are set up in the Volcengine Identity console and the CLI
only references discovery_url + allowed_ids. custom_jwt deploys record
{url, runtime_id, auth_type, discovery_url, allowed_ids} in harness.json.
Verified end-to-end against a real user pool: deploy -> runtime Ready with a
custom_jwt authorizer carrying the given discovery_url + allowed_clients, no
key_auth. Docs (zh/en) updated.
warm-wm
approved these changes
Jun 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds a deployable Harness server (
veadk.cloud.harness_app) and aveadk harnessCLI to scaffold, configure, deploy, and invoke it on Volcengine AgentKit — no app code to write, no local Docker.A harness = an env-assembled agent spec (model + system prompt + tools + skills + knowledgebase/memory), described by a layered
harness.yaml, served atPOST /harness/invoke.CLI
create→add→show→deploy→invokeharness.yaml/.env.example/Dockerfile/README.md).harness.yaml;--tools/--skillscomma lists + per-component--<component>-<param>connection flags.harness.json.--name(url/key resolved fromharness.json); per-call once-time overrides (incremental tools/skills; memory/kb never overridable).OAuth2 / JWT deploy (custom_jwt)
An
authblock inharness.yaml(or--discovery-url/--allowed-id) gates the runtime via a Volcengine Identity user pool:auth=custom_jwt; absence = the existingkey_authpath (unchanged).authis excluded from the flattened runtime env — it only configures the gateway authorizer.discovery_url+allowed_ids.custom_jwtauthorizer carrying the givendiscovery_url+allowed_clients, nokey_auth.Tests / docs
tests/cloud/test_harness_app_contract.py,tests/cli/test_cli_agentkit_harness_contract.py); full suite green (278 passed).ruff+pyrightclean.docs/content/docs/cli/harness-cli.{mdx,en.mdx}+ example14_harness_server_on_agentkitrewritten for the current flow.🤖 Generated with Claude Code