{"id":42598299,"url":"https://github.com/agentsystems/agent-control-plane","last_synced_at":"2026-01-29T00:13:38.455Z","repository":{"id":313335897,"uuid":"1003289437","full_name":"agentsystems/agent-control-plane","owner":"agentsystems","description":"Gateway and orchestration for AI agent deployment","archived":false,"fork":false,"pushed_at":"2025-11-02T20:43:56.000Z","size":325,"stargazers_count":1,"open_issues_count":1,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-27T20:37:47.886Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://agentsystems.ai","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/agentsystems.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":".github/SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-06-16T23:28:16.000Z","updated_at":"2025-11-06T02:19:39.000Z","dependencies_parsed_at":"2025-10-14T23:16:05.196Z","dependency_job_id":null,"html_url":"https://github.com/agentsystems/agent-control-plane","commit_stats":null,"previous_names":["agentsystems/agent-control-plane"],"tags_count":67,"template":false,"template_full_name":null,"purl":"pkg:github/agentsystems/agent-control-plane","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agentsystems%2Fagent-control-plane","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agentsystems%2Fagent-control-plane/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agentsystems%2Fagent-control-plane/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agentsystems%2Fagent-control-plane/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/agentsystems","download_url":"https://codeload.github.com/agentsystems/agent-control-plane/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agentsystems%2Fagent-control-plane/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28857232,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-28T22:56:21.783Z","status":"ssl_error","status_checked_at":"2026-01-28T22:56:00.861Z","response_time":57,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-01-29T00:13:37.623Z","updated_at":"2026-01-29T00:13:38.446Z","avatar_url":"https://github.com/agentsystems.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Agent Control Plane\n\n[![GitHub stars](https://img.shields.io/github/stars/agentsystems/agentsystems?style=flat-square\u0026logo=github)](https://github.com/agentsystems/agentsystems/stargazers)\n[![CI](https://github.com/agentsystems/agent-control-plane/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/agentsystems/agent-control-plane/actions/workflows/ci.yml) [![codecov](https://codecov.io/gh/agentsystems/agent-control-plane/graph/badge.svg?token=C8QBKRD06Z)](https://codecov.io/gh/agentsystems/agent-control-plane)\n\n\u003e [!NOTE]\n\u003e **Pre-Release Software** - AgentSystems is in active development. Join our [Discord](https://discord.com/invite/JsxDxQ5zfV) for updates and early access.\n\u003e ⭐ [**Star the main repository**](https://github.com/agentsystems/agentsystems) to show your support!\n\n\u003e This is the **gateway and orchestration layer** for AgentSystems. See the [main repository](https://github.com/agentsystems/agentsystems) for platform overview and documentation.\n\nThe **Agent Control Plane** (ACP) is the HTTP gateway and core services layer that fronts every AgentSystems deployment.\n\n* Repo: `agentsystems/agent-control-plane`\n* Image: `ghcr.io/agentsystems/agent-control-plane:\u003ctag\u003e` (publicly available)\n* Part of the multi-repository platform – see the [AgentSystems docs](https://github.com/agentsystems/agentsystems).\n\n---\n\n## Contents\n\n| Path | Purpose |\n|------|---------|\n| `cmd/gateway/` | FastAPI gateway \u0026 reverse-proxy (modularized components) |\n| ├── `main.py` | Core FastAPI application and endpoints |\n| ├── `database.py` | PostgreSQL connection pooling and job management |\n| ├── `docker_discovery.py` | Docker container discovery and agent registration |\n| ├── `egress.py` | Egress allowlist configuration and management |\n| ├── `lifecycle.py` | Container idle timeout and lifecycle management |\n| ├── `proxy.py` | HTTP CONNECT proxy server for agent egress |\n| ├── `models.py` | Pydantic data models |\n| └── `exceptions.py` | Common HTTP exception patterns |\n| `Dockerfile` | Container image build instructions |\n| `tests/` | Unit tests for gateway functionality |\n| `.coveragerc` | Test coverage configuration |\n| `CHANGELOG.md` | Version history and changes |\n\n---\n\n## How ACP fits into the platform\n\n```mermaid\ngraph LR\n  C((Client)) -- 18080 --\u003e G[Gateway]\n  subgraph \"agents-int\"\n    G -- 8080 --\u003e A1((hello-world-agent))\n    G --\u003e A2((your-agent))\n  end\n  G --\u003e PG[(Postgres)]\n\n```\n\n1. Gateway discovers containers with labels `agent.enabled=true` \u0026 `agent.port=\u003cport\u003e`.\n2. Auth (Bearer token placeholder) → forward to agent.\n3. Writes an append-only **audit** row (hash-chained).\n\nEndpoint details: [Gateway API](../docs/reference/gateway-api).\n\n---\n\n## Quick start\n\n### Using AgentSystems SDK (Recommended)\n\n```bash\n# Install the SDK\npipx install agentsystems-sdk\n\n# Initialize a deployment\nagentsystems init\n\n# Start the platform\ncd agent-platform-deployments\nagentsystems up\n```\n\n• API Gateway: \u003chttp://localhost:18080\u003e\n• List agents: `curl http://localhost:18080/agents -H \"Authorization: Bearer demo\"`\n\n### Using Docker directly\n\n```bash\n# Pull the public image\ndocker pull ghcr.io/agentsystems/agent-control-plane:latest\n\n# Run with Docker Compose (see agent-platform-deployments repo)\ndocker run -d \\\n  --name agent-control-plane \\\n  -p 18080:8080 \\\n  -v /var/run/docker.sock:/var/run/docker.sock \\\n  ghcr.io/agentsystems/agent-control-plane:latest\n```\n\n---\n\n## Local dev (hot reload)\n\n```bash\ncd agent-control-plane\npython -m venv .venv \u0026\u0026 source .venv/bin/activate\npip install -r requirements-dev.txt\n# override port via env if desired\nACP_BIND_PORT=8088 uvicorn cmd.gateway.main:app --reload --port ${ACP_BIND_PORT:-8080}\n```\n\n### Running tests\n\n```bash\n# Run all tests with coverage\npytest --cov=cmd --cov-report=term-missing\n\n# Run specific test file\npytest tests/test_gateway.py -v\n```\n\n---\n\n## Docker Images\n\n### Using the public image (Recommended)\n\n```bash\n# Pull the latest published image from GitHub Container Registry\ndocker pull ghcr.io/agentsystems/agent-control-plane:latest\n\n# Specific version\ndocker pull ghcr.io/agentsystems/agent-control-plane:0.3.3\n```\n\n### Building locally\n\n```bash\n# Clone and build for development\ngit clone https://github.com/agentsystems/agent-control-plane.git\ncd agent-control-plane\ndocker build -t my-custom-acp:dev .\n```\n\nIf you built a custom image, update the tag in your `docker-compose.yml` or `agentsystems-config.yml`.\n\n---\n\n## File Uploads \u0026 Artifacts\n\nThe gateway supports file uploads to agents and manages a shared artifacts volume.\n\n### Upload Endpoint\n\nSend multipart requests to any agent:\n\n```bash\n# Upload single file with JSON payload\ncurl -X POST http://localhost:18080/invoke/agent-name \\\n  -H \"Authorization: Bearer token\" \\\n  -F \"file=@data.csv\" \\\n  -F 'json={\"sync\": true, \"format\": \"csv\"}'\n\n# Upload multiple files\ncurl -X POST http://localhost:18080/invoke/agent-name \\\n  -H \"Authorization: Bearer token\" \\\n  -F \"file=@input1.txt\" \\\n  -F \"file=@input2.txt\" \\\n  -F 'json={\"sync\": true}'\n```\n\n### Artifacts Volume Management\n\nThe gateway automatically:\n\n1. **Creates thread directories**: `/artifacts/{thread-id}/{in,out}/` for each request\n2. **Saves uploaded files**: Files go to `/artifacts/{thread-id}/in/{filename}`\n3. **Sets permissions**: Attempts to configure agents (UID 1001) for file access\n4. **Configured with limits**: Default 200MB upload limit (configurable via `ACP_MAX_UPLOAD_MB`)\n\n### Thread-Centric Structure\n\n```\n/artifacts/\n├── {thread-id-1}/\n│   ├── in/          # Files uploaded by client\n│   │   ├── data.csv\n│   │   └── config.json\n│   └── out/         # Files created by agent\n│       └── result.txt\n└── {thread-id-2}/\n    ├── in/\n    └── out/\n```\n\n### Gateway Environment Variables\n\n| Var | Default | Purpose |\n|-----|---------|---------|\n| `ACP_MAX_UPLOAD_MB` | `200` | Maximum file upload size in MB |\n| `ACP_BIND_PORT` | `8080` | Gateway listen port inside container |\n| `ACP_AUDIT_DSN` | `postgresql://...` | Postgres connection for audit logs |\n| `ACP_PROXY_PORT` | `3128` | HTTP CONNECT proxy port for agent egress |\n| `ACP_IDLE_TIMEOUT_MIN` | `15` | Default idle timeout for containers (minutes) |\n| `AGENTSYSTEMS_CONFIG_PATH` | `/etc/agentsystems/agentsystems-config.yml` | Path to agent configuration file |\n\n### Accessing Artifacts\n\nView uploaded files and agent outputs:\n\n```bash\n# List all active threads\ndocker exec gateway ls -la /artifacts/\n\n# Read specific files\ndocker exec gateway cat /artifacts/{thread-id}/out/result.json\n```\n\n---\n\n## Configuration\n\n## Continuous Integration (GitHub Actions)\n\nEvery pull request triggers `ci.yml` which now performs:\n\n1. Pre-commit hooks (ruff, black, shellcheck, hadolint).\n2. `docker build` of the gateway image.\n3. Run the container on `localhost:8800` (internal port 8080).\n4. Poll `http://localhost:8800/health` (30 × 2 s) and fail if not **200 OK**.\n5. Always remove the container in a cleanup step.\n\nThe gateway detects when the host Docker socket is absent (e.g. CI) and gracefully disables agent discovery, emitting the log line `docker_unavailable`. The health endpoint still reports **OK**, so the build remains deterministic.\n\n---\n\n### Environment variables (excerpt)\n\n| Var | Default | Purpose |\n|-----|---------|---------|\n| `PG_HOST` | `localhost` | Postgres host |\n| `PG_DB` | `agent_cp` | Postgres database name |\n| `PG_USER` | `agent` | Postgres user |\n| `PG_PASSWORD` | `agent` | Postgres password |\n\n### Agent discovery labels\n\n| Label | Example | Meaning |\n|-------|---------|---------|\n| `agent.enabled` | `true` | Opt-in to gateway routing. |\n| `agent.port` | `8000` | TCP port the agent listens on. |\n\n---\n\n## Architecture\n\n### Module Structure\n\nThe gateway is organized into focused modules:\n\n- **`main.py`**: FastAPI application, request routing, and API endpoints\n- **`docker_discovery.py`**: Container discovery via Docker labels, maintains agent registry\n- **`database.py`**: PostgreSQL operations with automatic fallback to in-memory storage\n- **`egress.py`**: Loads and manages per-agent egress allowlists from config\n- **`proxy.py`**: HTTP CONNECT proxy server for controlled agent outbound requests\n- **`lifecycle.py`**: Monitors agent activity and stops idle containers\n- **`models.py`**: Shared Pydantic models for request/response validation\n- **`exceptions.py`**: Standardized HTTP exception factories\n\n### Key Features\n\n1. **Auto-discovery**: Finds agents by Docker labels (`agent.enabled=true`)\n2. **Lazy start**: Automatically starts stopped agent containers on first request\n3. **Idle management**: Stops containers after configurable idle timeout\n4. **Egress control**: HTTP proxy configured to restrict agent outbound requests to allowlisted URLs\n5. **File uploads**: Handles multipart uploads with automatic artifact management\n6. **Async by default**: Non-blocking invocations with status polling\n7. **Type safety**: Full type hints for better IDE support\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines on contributing to this project.\n\n### Development Guidelines\n\n- Add type hints to all new functions\n- Include docstrings for public APIs\n- Update CHANGELOG.md for notable changes\n- Run tests before submitting PRs: `pytest`\n\n---\n\n\u003c!--\n## Legacy README\n\n**Agent Control Plane** (ACP) is the HTTP gateway and set of core micro-services that sit in front of every AgentSystems deployment.\n\n* Repository root: `agentsystems/agent-control-plane`\n* Container image: `agentsystems/agent-control-plane:\u003ctag\u003e`\n* Part of the wider multi-repo platform – see the [docs site](../docs/overview) for the big picture.\n\nThis repository contains the **gateway runtime** and libraries that power the Agent Platform. It no longer carries any Docker-Compose assets – those now live in the separate [`agent-platform-deployments`](https://github.com/agentsystems/agent-platform-deployments) repository.\n\n\n\n## Contents\n\n| Path | Purpose |\n|------|---------|\n| `cmd/gateway/` | FastAPI HTTP gateway \u0026 reverse-proxy. |\n| `audit/` | Postgres writer + hash-chain trigger (tamper-evident). |\n| `model_router/` | (WIP) Policy-based model selection. |\n| `examples/agents/` | Example agents generated from the [agent-template](https://github.com/agentsystems/agent-template). |\n| - | - |\n| `cmd/gateway/` | FastAPI gateway that discovers agent containers via Docker labels and proxies requests. |\n| `model_router/` | (WIP) Simple model selection helper. |\n| `audit/` | (Planned) Append-only Postgres audit writer. |\n| `examples/agents/` | Minimal example agents built from the [agent-template](https://github.com/agentsystems/agent-template). |\n\n\n\n## How ACP fits into the platform\n\n```mermaid\ngraph LR\n  client((Client)) -- 18080 --\u003e gateway[Gateway]\n  subgraph \"Docker network: agents-int\"\n    gateway -- 8080 --\u003e agent1((some-agent))\n    gateway --\u003e agent2((another-agent))\n  end\n  gateway --\u003e pg[(Postgres)]\n  gateway --\u003e lf[Langfuse]\n```\n\n1. **Gateway** discovers containers on the `agents-int` internal network via Docker/Kubernetes labels `agent.enabled=true` and `agent.port=\u003cport\u003e`.\n2. Requests are authenticated (Bearer token placeholder for now) and forwarded to the agent container.\n3. Each round-trip is appended to the **audit** table (hash-chained rows) and optionally mirrored to Langfuse.\n\nSee the [Gateway API reference](../docs/reference/gateway-api) for endpoints.\n\n## Quick start (compose)\n\nThe fastest path is the deployment repo:\n\n```bash\n# clone side-by-side\nmkdir agents \u0026\u0026 cd agents\nfor repo in agent-control-plane agent-platform-deployments agent-template; do\n  git clone https://github.com/agentsystems/$repo.git\ndone\n\ncd agent-platform-deployments\nmake up        # docker compose up -d (gateway + Postgres + example agent)\n```\n\nBrowse:\n• Gateway Swagger UI → \u003chttp://localhost:18080/hello-world-agent/docs\u003e\n• List agents \u0026 states → `curl http://localhost:18080/agents -H \"Authorization: Bearer demo\"`\n  Returns JSON array of objects like `{ \"name\": \"hello-world-agent\", \"state\": \"running\" }`\n\n## Local development (hot reload)\n\n```bash\ncd agent-control-plane\npython -m venv .venv \u0026\u0026 source .venv/bin/activate\npip install -e .[dev]\n# override port via env if desired\nACP_BIND_PORT=8088 uvicorn cmd.gateway.main:app --reload --port ${ACP_BIND_PORT:-8080}\n```\n\nPoint the deployment’s compose file at `host.docker.internal:8080` or run an agent locally on port 8000 and the gateway will pick it up.\n\n## Building the container\n\n\nThis repo is intended to be **built into a container image** and then orchestrated via the manifests in [`agent-platform-deployments`](https://github.com/agentsystems/agent-platform-deployments).\n\n```\n# clone\n git clone https://github.com/agentsystems/agent-control-plane.git\n cd agent-control-plane\n\n# build image (adjust tag as needed)\n docker build -t agentsystems/agent-control-plane:\u003ctag\u003e .\n```\n\nPush the image to your registry of choice and update the image tag in the deployment repo’s Compose / Helm charts.\n\n\n\n```\n \u0026\u0026 source .venv/bin/activate\npip install -e .[dev]\n# override port via env if desired\nACP_BIND_PORT=8088 uvicorn cmd.gateway.main:app --port ${ACP_BIND_PORT:-8080}\n```\n\nBut day-to-day you will spin it up via the deployment bundle, e.g.:\n\n```\n# in agent-platform-deployments\n\n```\n\n```\n# clone\ngit clone https://github.com/agentsystems/agent-control-plane.git\ncd agent-control-plane\n\n# create venv \u0026 install\n \u0026\u0026 source .venv/bin/activate\npip install -e .[dev]\n\n# run gateway\n# override port via env if desired\nACP_BIND_PORT=8088 uvicorn cmd.gateway.main:app --reload --port ${ACP_BIND_PORT:-8080}\n```\n\n (either with Docker or `uvicorn agent.main:app`) and the gateway auto-registers when the container is labeled `agent.enabled=true` and exposes the configured port (once health checks pass).\n\n (gateway + Postgres + example agent, etc.) use the **agent-platform-deployments** repo:\n\n```bash\n# in a separate clone\ncd agent-platform-deployments\ndocker compose -f compose/local/docker-compose.yml up -d\n```\n\n\n\n## Configuration \u0026 conventions\n\nEnvironment variables (excerpt):\n\n| Var | Default | Purpose |\n|-----|---------|---------|\n| `ACP_BIND_PORT` | `8080` | Gateway listen port inside the container. |\n| `ACP_AUDIT_DSN` | `postgresql://user:pw@postgres:5432/acp` | Audit Postgres connection. |\n| `ACP_ALLOWED_ORIGINS` | `*` | CORS origins. |\n\nAgent discovery labels:\n\n| Label | Example | Meaning |\n|-------|---------|---------|\n| `agent.enabled` | `true`  | Opt-in to gateway routing. |\n| `agent.port`    | `8000`  | Container port to forward to. |\n\n## Release checklist\n1. Bump version in `pyproject.toml`.\n2. Build \u0026 push Docker image: `docker build -t agentsystems/agent-control-plane:\u003ctag\u003e .`.\n3. Create Git tag and release notes.\n4. Update Compose / Helm charts in `agent-platform-deployments` with the new `\u003ctag\u003e`.\n\n\n © 2025 AgentSystems\n\n\n\n + (includes Compose v2)\n\n\n\n\n\n          # repo root\ndocker compose build                  # build agents + gateway\ndocker compose up -d                  # start stack (detached)\ncurl http://localhost:18080/agents | jq .   # → `{ \"agents\": [ {\"name\": \"hello-world-agent\", \"state\": \"running\"}, ... ] }`\n```\n\nSwagger for any agent:\n\u003chttp://localhost:18080/my_agent/docs\u003e\n\n\n\n\n\nInvoke an agent and poll status until it completes:\n\n```bash\n# 1. Start the job (returns thread_id and helper URLs)\nresp=$(curl -s -X POST http://localhost:18080/invoke/my_agent \\\n     -H \"Content-Type: application/json\" \\\n     -d '{\"today\":\"2025-06-13\"}')\nthread_id=$(echo \"$resp\" | jq -r .thread_id)\n\n# 2. Poll lightweight status endpoint (state + progress only)\ncurl -s http://localhost:18080/status/$thread_id | jq .\n# { \"state\": \"running\", \"progress\": { ... } }\n\n# 3. Fetch the final result when state == completed\ncurl -s http://localhost:18080/result/$thread_id | jq .\n# { \"result\": { ... } }\n```\n\n\n\n\n\n```bash\ndocker compose down        # stop containers, keep images\ndocker system prune -f     # optional: clear build cache\n```\n\n\n\n\n\n```bash\n# copy an existing folder\ncp -R my_agent my_fourth_agent\n\n# edit YAML metadata\nsed -i '' 's/name:.*/name: my_fourth_agent/' my_fourth_agent/agent.yaml\n\n# (optional) tweak greeting\nsed -i '' 's/Hello!/Howdy from agent four!/' my_fourth_agent/main.py\n```\n\nAppend this to **docker-compose.yml**:\n\n```yaml\nmy_fourth_agent:\n  build: ./my_fourth_agent\n  expose: [\"8000\"]\n  labels:\n    - agent.enabled=true\n    - agent.port=8000\n```\n\nThen:\n\n```bash\ndocker compose build my_fourth_agent\ndocker compose up -d my_fourth_agent\ncurl http://localhost:18080/agents | jq .   # shows `{ \"name\": \"my_fourth_agent\", \"state\": \"running\" }`\ncurl -X POST http://localhost:18080/invoke/my_fourth_agent \\\n     -H \"Content-Type: application/json\" \\\n     -d '{\"today\":\"2025-06-13\"}'\n```\n\n\n\n\n\n + label discovery (`/gateway`)\nAgents   → FastAPI apps in `my_*_agent/`, read their own `agent.yaml`\nLabels   → `agent.enabled=true` \u0026 `agent.port=8000` tell the gateway to route\n--\u003e\n\n## License\n\nLicensed under the [Apache-2.0 license](./LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagentsystems%2Fagent-control-plane","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fagentsystems%2Fagent-control-plane","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagentsystems%2Fagent-control-plane/lists"}