Run the connector fleet quickstart
In this tutorial, you will start the repository’s deterministic connector-fleet
topology and route one signed AIP action from aipctl, through a
product-neutral aipd gateway, to a standalone Cal.diy connector host. The
provider is a controlled local fixture, so the exercise needs no external Cal
account or product credential.
This is a learning path for the fleet process boundary. It is not a production
deployment or a qualification run. The reviewed source is commit
97be86e9efedf07ecf1783b03800f683f107fb04.
What you will observe
By the end of the tutorial, you will have observed:
- source-derived container image and connector release identities;
- registry admission before a connector host starts;
- two product-neutral gateway replicas and one lifecycle control plane;
- one healthy Cal.diy connector replica for
tenant-acme; - a signed call to
cap:cal_diy:profile.getwith statuscompleted; - durable action lookup through either gateway replica;
- bounded removal of only the named tutorial stack and its volumes.
The reference Compose file also defines deterministic hosts for Hermes Agent, Chatwoot, Dify, and CrewAI. This tutorial builds those images but starts only the Cal.diy product path. Twenty is one of the six maintained connectors, but it has no service in this deterministic fixture and follows its own deployment and qualification path.
Prerequisites
You need:
- a clean checkout at the reviewed source revision;
- Docker Engine with Docker Compose v2 and BuildKit;
- enough local CPU, memory, and disk for a source-based multi-image build;
- TCP port
18443free on the loopback interface; - a POSIX-compatible shell and
lsoffor the port preflight.
Run every command from the aip-core repository root. The first preparation
can take substantially longer than the native quickstart because it builds the
gateway, control plane, fixtures, and five product-host images.
The Compose project has the fixed name aip-connector-fleet-qualification.
Do not use this tutorial while another run is using that project or while its
volumes contain evidence you need to retain.
1. Verify the source and Docker boundary
Confirm the exact source revision, a clean worktree, and an available Docker daemon:
export AIP_SOURCE_REVISION=97be86e9efedf07ecf1783b03800f683f107fb04
test "$(git rev-parse HEAD)" = "$AIP_SOURCE_REVISION"
test -z "$(git status --porcelain)"
docker info >/dev/null
docker compose version
All four checks must exit with status 0. If the worktree is not clean, use a
separate clean checkout instead of hiding changes: the preparation script
derives image and release identities from the complete workspace content.
Check that the fixed host port is unused:
if ! command -v lsof >/dev/null; then
echo "lsof is required for the port preflight" >&2
exit 1
fi
if lsof -nP -iTCP:18443 -sTCP:LISTEN | grep -q .; then
echo "Port 18443 is already in use" >&2
exit 1
fi
Expected result: the command prints nothing and exits with status 0.
2. Prepare source-derived images
Build the exact images and write their immutable image IDs to the generated Compose environment:
./deploy/connector-fleet/prepare.sh
test -s deploy/connector-fleet/.env.qualification
Expected result: the script ends with a line beginning
connector fleet preparation: PASS. The generated file contains source,
image, and release metadata for this workspace. At the reviewed revision it
does not contain product credentials.
Define a short shell helper for the remaining commands:
compose() {
docker compose \
--profile products \
--env-file deploy/connector-fleet/.env.qualification \
-f deploy/connector-fleet/compose.yml \
"$@"
}
Inspect the fixed Compose project before changing it:
compose ps --all
If this lists containers from another investigation or qualification run, stop here and preserve that run first. This tutorial deliberately does not rename the project because the source-owned volume and evidence tooling use its fixed identity.
3. Start one product path
Start the Cal.diy host and its declared dependencies, and wait for running services to become healthy:
compose up --detach --wait --wait-timeout 300 cal-acme-a
Expected result: the command exits with status 0. Compose runs short-lived
initializers and admission jobs before it reports the long-running services as
healthy. The dependency graph starts:
- PostgreSQL and registry initialization;
- deterministic identity, policy, secret, and product fixtures;
- the connector lifecycle control plane;
- the TLS edge;
aipdandaipd-bagainst shared durable state;- the controlled product upstream;
cal-acme-aas a standalone connector host.
The setup graph also creates qualification-only admission artifacts. They are internal test infrastructure, not additional public product connectors, and their host services are not part of this tutorial outcome.
Inspect both completed setup jobs and running services:
compose ps --all
cal-acme-a, aipd, aipd-b, control-plane, edge, postgres, and
product-upstream should be running and healthy. Initialization and admission
services may be exited with status 0 because they are one-shot jobs.
4. Route one signed read
Run aipctl inside the isolated fleet network. The command mounts the
source-generated client key, gateway DID, and local TLS authority from the
Compose volumes:
compose run --rm --no-deps \
--entrypoint /usr/local/bin/aipctl \
-e AIPCTL_NATIVE_PRINCIPAL_ID=service:aipctl:qualification-acme \
-e AIPCTL_NATIVE_TRUST_DOMAIN=fleet.test \
-e AIPCTL_NATIVE_SIGNING_SEED_FILE=/fleet-state/secrets/client-acme-signing-seed.hex \
-e AIPCTL_NATIVE_PEER_DID_FILE=/fleet-state/public/gateway.did \
-e AIPCTL_NATIVE_TLS_CA_FILE=/caddy-data/caddy/pki/authorities/local/root.crt \
qualification action call \
https://aipd.fleet.test:8443 \
cap:cal_diy:profile.get \
--action-id act_connector_fleet_quickstart_001 \
--input '{}'
Expected result: the response is an AIP action result whose action_id is
act_connector_fleet_quickstart_001 and whose status is completed. The
output contains the deterministic Cal.diy profile returned by the controlled
upstream.
This completion demonstrates the configured local path: signed client request, gateway authentication, tenant-scoped capability routing, connector-host execution, and a product-shaped fixture response. It does not demonstrate behavior against a live Cal.diy deployment.
5. Read the action through the second gateway
Query the shared durable action state through aipd-b without replaying the
provider operation:
compose run --rm --no-deps \
--entrypoint /usr/local/bin/aipctl \
-e AIPCTL_NATIVE_PRINCIPAL_ID=service:aipctl:qualification-acme \
-e AIPCTL_NATIVE_TRUST_DOMAIN=fleet.test \
-e AIPCTL_NATIVE_SIGNING_SEED_FILE=/fleet-state/secrets/client-acme-signing-seed.hex \
-e AIPCTL_NATIVE_PEER_DID_FILE=/fleet-state/public/gateway.did \
-e AIPCTL_NATIVE_TLS_CA_FILE=/caddy-data/caddy/pki/authorities/local/root.crt \
-e AIPCTL_NATIVE_BEARER_TOKEN_FILE=/fleet-state/secrets/native-bearer-token \
qualification action status \
https://aipd-b.fleet.test:8443 \
act_connector_fleet_quickstart_001 \
--include-result \
--include-receipts
Expected result: the lifecycle view identifies the same action and capability,
reports a terminal state with result_status set to completed, and includes
the stored result. A successful lookup shows that the two gateway replicas use
the same durable runtime state; it is not a failover or recovery test.
6. Verify the tutorial outcome
Repeat a non-mutating status lookup and require both the connector host and gateways to remain healthy:
test "$(compose ps --status running --services | grep -cx 'cal-acme-a')" -eq 1
test "$(compose ps --status running --services | grep -Ec '^aipd(-b)?$')" -eq 2
compose run --rm --no-deps \
--entrypoint /usr/local/bin/aipctl \
-e AIPCTL_NATIVE_PRINCIPAL_ID=service:aipctl:qualification-acme \
-e AIPCTL_NATIVE_TRUST_DOMAIN=fleet.test \
-e AIPCTL_NATIVE_SIGNING_SEED_FILE=/fleet-state/secrets/client-acme-signing-seed.hex \
-e AIPCTL_NATIVE_PEER_DID_FILE=/fleet-state/public/gateway.did \
-e AIPCTL_NATIVE_TLS_CA_FILE=/caddy-data/caddy/pki/authorities/local/root.crt \
-e AIPCTL_NATIVE_BEARER_TOKEN_FILE=/fleet-state/secrets/native-bearer-token \
qualification action status \
https://aipd.fleet.test:8443 \
act_connector_fleet_quickstart_001 \
--include-result >/dev/null
All three commands must exit with status 0. You have now observed admission,
registration, signed routing, standalone execution, and shared durable lookup
for one low-risk product capability.
Stop and clean up
Before deletion, capture diagnostics if any step failed:
compose ps --all
compose logs --no-color --tail 200 aipd aipd-b control-plane cal-acme-a
When no retained state from this named project is needed, remove its containers, network, and volumes:
compose down --volumes --remove-orphans --timeout 30
test -z "$(compose ps --all --quiet)"
The first command deletes the project volumes, including PostgreSQL state, generated keys, and any qualification evidence stored there. It does not prune unrelated containers, images, build cache, or volumes. Keep the images if you intend to repeat the tutorial; remove them only through a separately reviewed cleanup decision.
Resolve common failures
| Symptom | Decision |
|---|---|
| Preparation reports that Docker is unavailable | Start or repair the Docker daemon, then rerun the same source check before preparation |
Port 18443 is already in use |
Identify the owning process or existing fleet run; do not stop or delete it without confirming ownership |
| An image build fails | Preserve the build output, confirm disk and tool availability, and rerun prepare.sh from the same clean revision |
| A one-shot admission job exits nonzero | Inspect compose ps --all and that job’s logs; do not bypass admission or start the host manually |
| A service does not become healthy | Inspect the named service, its dependency state, and bounded logs before cleanup |
| The signed action is rejected | Confirm that the command uses the generated principal, key, peer DID, CA, and tenant-acme fixture unchanged |
| The action completes but the second lookup fails | Preserve gateway and PostgreSQL logs; this tutorial does not authorize recreating shared state as a repair |
What happened internally
The fixture generated trust material and immutable admission packages, migrated the connector registry, and admitted the Cal.diy connector version before its host process started. The host then registered a tenant-scoped replica and renewed its lease with the lifecycle control plane.
The signed aipctl request reached the product-neutral gateway. The gateway
selected an eligible Cal.diy replica from the registry and sent the action to
the standalone host. That host resolved its fixture credential, called the
controlled upstream, and returned a typed result. Both gateways used the same
PostgreSQL-backed runtime state, so the second gateway could read the completed
action without repeating the product call.
The repository’s full product-fleet qualification exercises all five fixture hosts, governed mutations, tenant isolation, durable replay, outages, restarts, and failover. Those checks belong to the qualification documentation and are intentionally outside this quickstart.