Skip to content
Merged
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
153 changes: 101 additions & 52 deletions references/apigee-skills-serving/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ custom MCP hosts, etc.) can discover and install.

This reference implementation shows how to:

1. **Author** a skill (a `SKILL.md` + optional `scripts/`) and describe it
with a `manifest.yaml` against a locked schema.
1. **Author** a skill (a `SKILL.md` + optional `scripts/`) and describe
it with a `manifest.yaml` against a locked schema.
2. **Sign** the skill bundle with an Ed25519 key so consumers can verify
integrity at install time.
3. **Upload** the signed `.skill` archive to a Google Cloud Storage bucket.
3. **Upload** the signed `.skill` archive to a Google Cloud Storage
bucket.
4. **Register** the skill (and its API hub attribute taxonomy) so it is
discoverable through API hub's search and attribute filters.
5. **Install** a skill on the consumer side: search API hub, fetch the
Expand All @@ -21,6 +22,20 @@ This reference implementation shows how to:
The whole loop runs on standard Apigee X / hybrid plus API hub — no
custom infrastructure.

Two ready-to-run agent skills wrap the reference implementation into
a one-line install for end users:

- **`skills/skill-finder/`** — consumer-side discovery client. Queries
API hub for signed skills, verifies their Ed25519 signatures against
locally-installed per-deployment trust roots, and installs matching
skills into the agent runtime's skills directory.
- **`skills/skill-publisher/`** — author-side pipeline orchestrator.
Wraps pack → sign → upload → register into a single skill an agent
can invoke on a source skill directory.

Both are installed by `bin/install-skill-finder.sh` (which installs
both by default).

## Why Apigee API hub for skills?

Agent skills are, structurally, just metadata-tagged content addressed
Expand Down Expand Up @@ -48,12 +63,17 @@ references/apigee-skills-serving/
├── pytest.ini test configuration
├── docs/
│ ├── architecture.md design overview and trust model
│ ├── publish-and-install.md end-to-end walkthrough
│ ├── provisioning.md customer-onboarding runbook (five-minute path)
│ ├── publish-and-install.md detailed end-to-end walkthrough (under-the-hood)
│ └── policy-skill-catalog.md about the apigee-policy-top10 example
├── bin/
│ ├── check-prerequisites.sh pre-flight environment validator
│ ├── demo-setup.sh env export + readiness print
│ └── demo-cleanup.sh remove demo artifacts
│ ├── demo-setup.sh env export + readiness print (legacy)
│ ├── demo-cleanup.sh remove locally-installed skills
│ ├── install-skill-finder.sh one-line installer for skill-finder + skill-publisher
│ ├── install-skill-publisher.sh install skill-publisher only
│ └── provision.sh one-line customer bootstrap (APIs, bucket,
│ taxonomy, key gen, publish, trust root)
├── schema/
│ └── skill-manifest.schema.yaml locked v1 manifest schema
├── scripts/ publisher-side toolchain
Expand All @@ -63,8 +83,10 @@ references/apigee-skills-serving/
│ ├── register_skill.py register the manifest with API hub
│ ├── update_taxonomy.py create/update API hub attribute taxonomy
│ └── common/ shared libraries (retry, IAM, schema)
├── skills/ example skills
│ ├── apigee-policy-top10/ skill that documents Apigee policy patterns
├── skills/ shipped skills
│ ├── skill-finder/ consumer-side discovery + install client
│ ├── skill-publisher/ author-side pipeline orchestrator
│ ├── apigee-policy-top10/ example skill that reports top Apigee policies
│ ├── currency-converter/ minimal example
│ └── weather-lookup/ minimal example
├── examples/
Expand Down Expand Up @@ -93,42 +115,54 @@ references/apigee-skills-serving/
6. The roles `roles/apihub.editor` and `roles/storage.objectCreator` on
the target project.

## Quickstart
## Quickstart (five minutes)

The fast path uses two shell scripts:

```bash
# 1. Clone and enter the reference
# 1. Install skill-finder + skill-publisher on your machine.
curl -fsSL https://raw.githubusercontent.com/apigee/devrel/main/\
references/apigee-skills-serving/bin/install-skill-finder.sh \
| bash -s -- --runtime gemini # or --runtime opencode / antigravity

# 2. Clone the reference and provision your GCP project.
git clone https://github.com/apigee/devrel.git
cd devrel/references/apigee-skills-serving
bash bin/provision.sh --project MY_PROJECT --yes
```

# 2. Install Python dependencies into a virtualenv
python3 -m venv .venv
. .venv/bin/activate
pip install -r requirements.txt
`provision.sh` enables the required GCP APIs, creates a GCS
bucket, sets up the API hub attribute taxonomy, generates a
fresh Ed25519 signing keypair on your machine (private key
stays there), and publishes the three example skills. Every
step is idempotent — re-run any time to reconcile drift.

Full runbook (including troubleshooting and key rotation):
[`docs/provisioning.md`](docs/provisioning.md).

### Under the hood

# 3. Set up environment variables (edit values to match your project)
cp env.sh.example env.sh
$EDITOR env.sh
. ./env.sh

# 4. Verify prerequisites
./bin/check-prerequisites.sh

# 5. (One-time) Create the API hub attribute taxonomy
python3 scripts/update_taxonomy.py \
--project "$APIHUB_PROJECT" \
--location "$APIHUB_LOCATION"

# 6. Pack, sign, upload, register a skill
python3 scripts/pack_skill.py skills/currency-converter /tmp/cc.skill
python3 scripts/sign_skill.py /tmp/cc.skill --key-file ./signing.key
python3 scripts/upload_skill.py /tmp/cc.skill --bucket "$GCS_BUCKET"
python3 scripts/register_skill.py \
--project "$APIHUB_PROJECT" --location "$APIHUB_LOCATION" \
--manifest /tmp/cc.skill
The scripts above chain the five underlying operations that
this reference exists to demonstrate:

```bash
# For each skill:
python3 -m scripts.pack_skill --src skills/<name> --out /tmp/<name>.skill
python3 -m scripts.upload_skill --zip /tmp/<name>.skill --bucket "$GCS_BUCKET"
python3 -m scripts.sign_skill --manifest <patched-manifest> \
--zip /tmp/<name>.skill \
--priv-key <signing.raw> \
--out <signed-manifest>
python3 -m scripts.register_skill --manifest <signed-manifest> \
--project "$APIHUB_PROJECT" \
--location "$APIHUB_LOCATION"
```

Full walkthrough: [`docs/publish-and-install.md`](docs/publish-and-install.md).
Design rationale and trust model: [`docs/architecture.md`](docs/architecture.md).
Full walkthrough:
[`docs/publish-and-install.md`](docs/publish-and-install.md).

Design rationale and trust model:
[`docs/architecture.md`](docs/architecture.md).

## Running the tests

Expand All @@ -144,26 +178,41 @@ pytest -q
`pipeline.sh` runs the same suite and is what apigee/devrel CI invokes
nightly.

## Example skills
## Shipped skills

| Skill | Purpose |
| ---------------------- | --------------------------------------------------------------------------------------------------- |
| `currency-converter` | Minimal example. A `SKILL.md` plus a `manifest.yaml`. Useful as a copy-and-edit starting point. |
| `weather-lookup` | Minimal example demonstrating a skill with API-key-based external HTTP calls. |
| `apigee-policy-top10` | A skill that documents the ten most useful Apigee policy patterns, with a script that enumerates |
| | the policies present in your org. See [`docs/policy-skill-catalog.md`](docs/policy-skill-catalog.md). |
| `examples/apigee-proxy-skill` | A complete, production-shaped skill: 18 MCP tools, 25 Jinja2 policy templates, full manifest. |
| Skill | Purpose |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `skill-finder` | Consumer-side. Discovers, verifies, and installs signed skills from the customer's API hub. Multi-key trust root; per-deployment provisioning. |
| `skill-publisher` | Author-side. Wraps pack → sign → upload → register into a single skill an agent can invoke on a source skill directory. |
| `currency-converter` | Minimal example. A `SKILL.md` plus a `manifest.yaml`. Useful as a copy-and-edit starting point. |
| `weather-lookup` | Minimal example demonstrating a skill with API-key-based external HTTP calls. |
| `apigee-policy-top10` | A skill that documents the ten most useful Apigee policy patterns, with a script that enumerates the policies present in your org. See [`docs/policy-skill-catalog.md`](docs/policy-skill-catalog.md). |
| `examples/apigee-proxy-skill` | A complete, production-shaped skill: 18 MCP tools, 25 Jinja2 policy templates, full manifest. |

## Limitations and non-goals

- The skill registry uses API hub's standard search; ranking is keyword
overlap, not semantic. For semantic ranking, integrate a vector
search component separately.
- The publisher and consumer share an Ed25519 trust root. Key rotation
is a manual operator workflow; this reference does not implement
automatic rotation.
- Skills are sandboxed by the consumer runtime (OpenCode, agent host).
This reference does not introduce additional sandboxing on top.
- The skill registry uses API hub's standard search; ranking is
keyword overlap, not semantic. For semantic ranking, integrate
a vector search component separately.
- The trust root is **per-deployment**, not shared. Each customer
who runs `provision.sh` generates their own Ed25519 keypair on
their machine. The `apigee/devrel` repo intentionally contains
no signing key material and no signed release bundles;
skill-finder itself is trusted by provenance (TLS + `apigee`
GitHub org). See
[`docs/architecture.md#trust-model`](docs/architecture.md#trust-model)
for the full rationale.
- Key rotation is a supported operator workflow (multi-key
trust root; add-then-remove pattern with no install-time gap),
but is not automated. See
[`docs/provisioning.md#key-rotation-with-zero-downtime`](docs/provisioning.md#key-rotation-with-zero-downtime).
- The GCS bucket for signed bundles must be public-read because
skill-finder downloads via anonymous HTTPS. This is a demo
choice; production would use signed URLs or an authenticated
consumer.
- Skills are sandboxed by the consumer runtime (OpenCode, Gemini
CLI, Antigravity, custom MCP hosts). This reference does not
introduce additional sandboxing on top.

## License

Expand Down
70 changes: 50 additions & 20 deletions references/apigee-skills-serving/bin/demo-setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
# If you re-target the demo at a different GCP project, edit
# these four lines. Everything else flows from here.

readonly DEMO_APIHUB_PROJECT="apigee-product-demo"
readonly DEMO_APIHUB_PROJECT="geirs-spaces-demo"
readonly DEMO_APIHUB_LOCATION="us-west1"
readonly DEMO_APIGEE_ORG="apigee-product-demo"
readonly DEMO_APIGEE_ORG="geirs-spaces-demo"
readonly DEMO_KEYWORD_OVERLAP="1"

# ---- Color codes -----------------------------------------
Expand Down Expand Up @@ -185,7 +185,14 @@ while [ $# -gt 0 ]; do
esac
done

# ---- Step 1: prereq check + ADC --------------------------
# ---- Step 1: ADC ----------------------------------------
#
# ADC is checked FIRST because check-prerequisites.sh also
# checks it and we want a specific, actionable failure line
# (`gcloud auth application-default login`) before the more
# generic prereq output. If ADC is broken, the prereq check
# would spend time on env-var checks whose answers don't
# matter until ADC is fixed.

echo "[setup] Verifying Application Default Credentials..."
if gcloud auth application-default print-access-token \
Expand All @@ -199,24 +206,22 @@ else
exit 1
fi

if [ "$skip_preflight" -eq 0 ]; then
echo
echo "[setup] Running pre-flight checker..."
if bash "${REPO_ROOT}/bin/check-prerequisites.sh"; then
_check "All required prerequisites met" 0
else
_check "Pre-flight failed" 1 \
"see [prereq] lines above"
echo
echo "Fix the failing prereqs, then re-run:"
echo " ./bin/demo-setup.sh"
exit 1
fi
else
echo "[setup] --skip-preflight given; pre-flight check skipped."
fi

# ---- Step 2: env export + persistent config --------------
#
# We MUST export the demo env vars BEFORE running the
# pre-flight checker. The checker reads APIHUB_PROJECT,
# APIHUB_LOCATION, APIGEE_ORG, and APIGEE_SKILLS_MIN_KEYWORD_OVERLAP
# from the current process environment. In a fresh shell (the
# common case -- an operator has just opened a terminal to
# start the demo), none of those are set yet. If we ran the
# checker before the export, it would fail on 3 of 4 required
# variables and abort, even though the demo is fully
# self-configuring and would work if we let it run.
#
# The persistent config file at ~/.config/apigee-skills-demo/
# is written here for the same reason: subprocesses launched
# without the exports still resolve the values via
# scripts/common/config.py's fallback.

_export_demo_env

Expand All @@ -233,6 +238,31 @@ echo "[setup] in the calling process)..."
_write_demo_config_file
echo

# ---- Step 3: pre-flight checker -------------------------
#
# Runs AFTER the export so the checker sees the demo values.
# The checker still enforces the invariant on behalf of an
# operator who prefers to source env.sh manually -- it just
# won't spuriously fail when the operator relied on this
# script to configure the shell.

if [ "$skip_preflight" -eq 0 ]; then
echo "[setup] Running pre-flight checker..."
if bash "${REPO_ROOT}/bin/check-prerequisites.sh"; then
_check "All required prerequisites met" 0
else
_check "Pre-flight failed" 1 \
"see [prereq] lines above"
echo
echo "Fix the failing prereqs, then re-run:"
echo " ./bin/demo-setup.sh"
exit 1
fi
else
echo "[setup] --skip-preflight given; pre-flight check skipped."
fi
echo

# ---- Step 3: ready --------------------------------------

echo -e "${GREEN}[setup] READY.${NC}"
Expand Down
Loading
Loading