Agents can be equipped with skills: reusable instruction packages in the Agent Skills format
(skills/<id>/SKILL.md, with optional text references). Skills for configuration-driven agents live
next to the agent definitions in
services/embabel-agent-service/agent-definitions/skills/.
A skill never grants tools: allowed-tools in a skill and text in instructions are ignored for tool
access. See A2A and configuration-driven agents.
The dashboard’s Skills Hub can additionally list skills from external Skills Marketplace connections. That marketplace integration is an early, placeholder contract, described below.
The ai-control-service can list skills from registered “Skills Marketplace” connections
(Skills Hub settings page) via GET /api/skill-catalog, using an invented placeholder wire
contract: GET {marketplaceUrl}/skills returning a JSON array of {name, description}
objects, authenticated with Authorization: Bearer <apiKey>. No real marketplace vendor
exists yet, so this repository ships a tiny fake marketplace (nginx serving a static
skills.json) purely so a developer can click through the feature by hand. It is
test/dev-only infrastructure: it has no build context, is not part of the default
docker compose up, is not referenced by any production code path or seed data, and is not
required by any automated test (those use an in-process HTTP double instead).
The mock is defined in a separate, never-auto-merged overlay file
(docker-compose.local-marketplace.yml, not docker-compose.override.yml). It only
starts when you explicitly add it with a second -f:
docker compose -f docker-compose.yml -f docker-compose.local-marketplace.yml up
Alternatively: ./scripts/stack-start.sh --with-local-marketplace.
A plain docker compose up (no overlay) never starts mock-skills-marketplace and never
touches the egress guard described below; the default startup path is unchanged.
SKILLS_MARKETPLACE_* environment variablesThese configure the ai-control-service outbound call to any registered marketplace
(real or mock). All have safe defaults and none are required for normal operation:
| Variable | Default | Meaning |
|---|---|---|
SKILLS_MARKETPLACE_REQUEST_TIMEOUT_SECONDS |
5 |
Overall per-marketplace request deadline, in seconds. |
SKILLS_MARKETPLACE_CONNECT_TIMEOUT_SECONDS |
2 |
TCP connect timeout, in seconds. |
SKILLS_MARKETPLACE_MAX_RESPONSE_BYTES |
262144 |
Maximum response body size (bytes) before the read is aborted. |
SKILLS_MARKETPLACE_MAX_ITEMS |
500 |
Maximum number of skill items accepted from one marketplace response. |
SKILLS_MARKETPLACE_MAX_REDIRECTS |
1 |
Maximum number of HTTP redirects followed. |
SKILLS_MARKETPLACE_MAX_CONNECTIONS_PER_FETCH |
25 |
Maximum number of marketplace connections queried in one fetch cycle. |
SKILLS_MARKETPLACE_ALLOW_PRIVATE_EGRESS |
false |
Deny-by-default egress guard opt-out for loopback/RFC1918/link-local/private destinations. See the warning below. |
http://mock-skills-marketplace/dev-mock-marketplace-key (the fixed, obviously-fake dev credential the mock
checks for; see infrastructure/mock-skills-marketplace/nginx.conf. It is never a
real secret and must never be reused anywhere else)skills.json fixture
(infrastructure/mock-skills-marketplace/skills.json) is returned as that connection’s
skill catalogue. An incorrect or missing API key gets a 401 from the mock, which the
feature reports as an authentication failure.No connection pointing at the mock is seeded anywhere. You must register it yourself through the settings UI.
SKILLS_MARKETPLACE_ALLOW_PRIVATE_EGRESS must never be set in any deployed environmentThis flag exists solely so the feature can be exercised against a marketplace that resolves
to a Docker-network private address (as the mock does). It relaxes the egress guard’s
deny-by-default policy for loopback, RFC1918, link-local, CGNAT, and IPv6 ULA destinations.
It is a local-development-only credential-guard relaxation, is off by default in both the
shipped application.yml and the base docker-compose.yml, and is only ever turned on by
the opt-in overlay above. Never set it in a staging or production environment.
Even with this flag enabled, cloud-metadata addresses (for example 169.254.169.254) stay
blocked. By design, the flag never widens the guard to cover metadata endpoints, regardless
of flag state.
/skills if the stored URL already ends in /skillsThe feature composes the request URL by appending /skills to the stored marketplace URL.
If you register a marketplace URL that already ends in /skills (e.g.
http://example.com/skills), the actual outbound request goes to
http://example.com/skills/skills. The Skills Hub settings page’s help text does not
currently warn about this. Fixing that help text is out of scope for this change; register
the marketplace’s base URL without a trailing /skills segment.