acp-gateway 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. acp_gateway-0.1.0/.dockerignore +9 -0
  2. acp_gateway-0.1.0/.env.example +12 -0
  3. acp_gateway-0.1.0/.gitattributes +3 -0
  4. acp_gateway-0.1.0/.githooks/pre-commit +6 -0
  5. acp_gateway-0.1.0/.github/workflows/linux-binary.yml +105 -0
  6. acp_gateway-0.1.0/.gitignore +40 -0
  7. acp_gateway-0.1.0/.python-version +1 -0
  8. acp_gateway-0.1.0/Dockerfile +19 -0
  9. acp_gateway-0.1.0/LICENSE +21 -0
  10. acp_gateway-0.1.0/PKG-INFO +309 -0
  11. acp_gateway-0.1.0/README.md +273 -0
  12. acp_gateway-0.1.0/config.example.yaml +49 -0
  13. acp_gateway-0.1.0/deploy/docker/compose.direct.yaml +6 -0
  14. acp_gateway-0.1.0/deploy/docker/compose.nginx.yaml +18 -0
  15. acp_gateway-0.1.0/deploy/docker/compose.yaml +40 -0
  16. acp_gateway-0.1.0/deploy/docker/computer.example.yaml +13 -0
  17. acp_gateway-0.1.0/deploy/docker/gateway.example.yaml +35 -0
  18. acp_gateway-0.1.0/deploy/docker/nginx-location.conf.example +19 -0
  19. acp_gateway-0.1.0/deploy/docker/nginx.conf.example +16 -0
  20. acp_gateway-0.1.0/deploy/docker/prepare.py +37 -0
  21. acp_gateway-0.1.0/deploy/windows/wsl-task.ps1 +65 -0
  22. acp_gateway-0.1.0/docs/architecture.md +536 -0
  23. acp_gateway-0.1.0/docs/archive/2026-10-06-initial-plan.md +1355 -0
  24. acp_gateway-0.1.0/docs/items/connector.md +459 -0
  25. acp_gateway-0.1.0/docs/setup/binary.md +103 -0
  26. acp_gateway-0.1.0/docs/setup/distribution.md +293 -0
  27. acp_gateway-0.1.0/docs/setup/gateway.md +132 -0
  28. acp_gateway-0.1.0/docs/setup/hermes.md +96 -0
  29. acp_gateway-0.1.0/docs/setup/observability.md +47 -0
  30. acp_gateway-0.1.0/docs/setup/service.md +236 -0
  31. acp_gateway-0.1.0/docs/setup/telegram.md +84 -0
  32. acp_gateway-0.1.0/docs/setup/vps-acceptance.md +277 -0
  33. acp_gateway-0.1.0/docs/setup/vps-acceptance.ru.md +296 -0
  34. acp_gateway-0.1.0/docs/setup/work-goose.md +90 -0
  35. acp_gateway-0.1.0/pyproject.toml +78 -0
  36. acp_gateway-0.1.0/road-map.md +581 -0
  37. acp_gateway-0.1.0/road-notes.md +1526 -0
  38. acp_gateway-0.1.0/scripts/binary_entry.py +9 -0
  39. acp_gateway-0.1.0/scripts/build_binary.py +96 -0
  40. acp_gateway-0.1.0/scripts/build_release.py +140 -0
  41. acp_gateway-0.1.0/scripts/check_secrets.py +153 -0
  42. acp_gateway-0.1.0/scripts/install.sh +38 -0
  43. acp_gateway-0.1.0/scripts/install_release.ps1 +48 -0
  44. acp_gateway-0.1.0/scripts/install_release.sh +60 -0
  45. acp_gateway-0.1.0/scripts/sanitize_fixture.py +65 -0
  46. acp_gateway-0.1.0/scripts/smoke_binary.py +346 -0
  47. acp_gateway-0.1.0/scripts/smoke_connector.py +162 -0
  48. acp_gateway-0.1.0/scripts/smoke_docker.py +320 -0
  49. acp_gateway-0.1.0/scripts/smoke_installation.py +245 -0
  50. acp_gateway-0.1.0/scripts/smoke_platform.py +249 -0
  51. acp_gateway-0.1.0/scripts/smoke_service.py +138 -0
  52. acp_gateway-0.1.0/scripts/smoke_wsl_task.ps1 +49 -0
  53. acp_gateway-0.1.0/scripts/spike_acp.py +562 -0
  54. acp_gateway-0.1.0/src/acp_gateway/__init__.py +10 -0
  55. acp_gateway-0.1.0/src/acp_gateway/__main__.py +3 -0
  56. acp_gateway-0.1.0/src/acp_gateway/agents/__init__.py +39 -0
  57. acp_gateway-0.1.0/src/acp_gateway/agents/client.py +632 -0
  58. acp_gateway-0.1.0/src/acp_gateway/agents/errors.py +39 -0
  59. acp_gateway-0.1.0/src/acp_gateway/agents/events.py +142 -0
  60. acp_gateway-0.1.0/src/acp_gateway/agents/tls.py +135 -0
  61. acp_gateway-0.1.0/src/acp_gateway/agents/transport.py +155 -0
  62. acp_gateway-0.1.0/src/acp_gateway/api/__init__.py +1 -0
  63. acp_gateway-0.1.0/src/acp_gateway/api/app.py +398 -0
  64. acp_gateway-0.1.0/src/acp_gateway/api/schemas.py +26 -0
  65. acp_gateway-0.1.0/src/acp_gateway/api/security.py +90 -0
  66. acp_gateway-0.1.0/src/acp_gateway/channels/__init__.py +5 -0
  67. acp_gateway-0.1.0/src/acp_gateway/channels/base.py +53 -0
  68. acp_gateway-0.1.0/src/acp_gateway/channels/cli.py +43 -0
  69. acp_gateway-0.1.0/src/acp_gateway/channels/mcp.py +196 -0
  70. acp_gateway-0.1.0/src/acp_gateway/channels/telegram.py +440 -0
  71. acp_gateway-0.1.0/src/acp_gateway/cli/__init__.py +0 -0
  72. acp_gateway-0.1.0/src/acp_gateway/cli/client.py +229 -0
  73. acp_gateway-0.1.0/src/acp_gateway/cli/computers.py +31 -0
  74. acp_gateway-0.1.0/src/acp_gateway/cli/main.py +309 -0
  75. acp_gateway-0.1.0/src/acp_gateway/config.py +384 -0
  76. acp_gateway-0.1.0/src/acp_gateway/connectors/__init__.py +1 -0
  77. acp_gateway-0.1.0/src/acp_gateway/connectors/commands.py +113 -0
  78. acp_gateway-0.1.0/src/acp_gateway/connectors/control.py +472 -0
  79. acp_gateway-0.1.0/src/acp_gateway/connectors/launch.py +70 -0
  80. acp_gateway-0.1.0/src/acp_gateway/connectors/policy.py +332 -0
  81. acp_gateway-0.1.0/src/acp_gateway/connectors/protocol.py +122 -0
  82. acp_gateway-0.1.0/src/acp_gateway/connectors/relay.py +381 -0
  83. acp_gateway-0.1.0/src/acp_gateway/core/__init__.py +55 -0
  84. acp_gateway-0.1.0/src/acp_gateway/core/approvals.py +224 -0
  85. acp_gateway-0.1.0/src/acp_gateway/core/bus.py +176 -0
  86. acp_gateway-0.1.0/src/acp_gateway/core/errors.py +27 -0
  87. acp_gateway-0.1.0/src/acp_gateway/core/gateway.py +404 -0
  88. acp_gateway-0.1.0/src/acp_gateway/core/policy.py +44 -0
  89. acp_gateway-0.1.0/src/acp_gateway/daemon.py +139 -0
  90. acp_gateway-0.1.0/src/acp_gateway/installation.py +318 -0
  91. acp_gateway-0.1.0/src/acp_gateway/log.py +267 -0
  92. acp_gateway-0.1.0/src/acp_gateway/maintenance_worker.py +270 -0
  93. acp_gateway-0.1.0/src/acp_gateway/paths.py +26 -0
  94. acp_gateway-0.1.0/src/acp_gateway/service.py +226 -0
  95. acp_gateway-0.1.0/src/acp_gateway/setup.py +69 -0
  96. acp_gateway-0.1.0/src/acp_gateway/storage/__init__.py +14 -0
  97. acp_gateway-0.1.0/src/acp_gateway/storage/computers.py +175 -0
  98. acp_gateway-0.1.0/src/acp_gateway/storage/db.py +435 -0
  99. acp_gateway-0.1.0/src/acp_gateway/storage/migrations/0001_initial.sql +41 -0
  100. acp_gateway-0.1.0/src/acp_gateway/storage/migrations/0002_approvals_audit.sql +21 -0
  101. acp_gateway-0.1.0/src/acp_gateway/storage/migrations/0003_channel_state.sql +7 -0
  102. acp_gateway-0.1.0/src/acp_gateway/storage/migrations/0004_computers.sql +9 -0
  103. acp_gateway-0.1.0/src/acp_gateway/storage/migrations/0005_computer_connections.sql +9 -0
  104. acp_gateway-0.1.0/src/acp_gateway/storage/migrations/__init__.py +0 -0
  105. acp_gateway-0.1.0/src/acp_gateway/storage/records.py +101 -0
  106. acp_gateway-0.1.0/tests/conftest.py +21 -0
  107. acp_gateway-0.1.0/tests/fakes/__init__.py +0 -0
  108. acp_gateway-0.1.0/tests/fakes/certs.py +64 -0
  109. acp_gateway-0.1.0/tests/fakes/fake_goose.py +326 -0
  110. acp_gateway-0.1.0/tests/fakes/hermes_probe.py +60 -0
  111. acp_gateway-0.1.0/tests/fakes/recordings.py +84 -0
  112. acp_gateway-0.1.0/tests/fakes/telegram.py +43 -0
  113. acp_gateway-0.1.0/tests/fixtures/acp/goose-1.53.0/cancel-during-command.jsonl +20 -0
  114. acp_gateway-0.1.0/tests/fixtures/acp/goose-1.53.0/cancel-during-generation.jsonl +16 -0
  115. acp_gateway-0.1.0/tests/fixtures/acp/goose-1.53.0/cancel-permission-pending.jsonl +20 -0
  116. acp_gateway-0.1.0/tests/fixtures/acp/goose-1.53.0/init.jsonl +2 -0
  117. acp_gateway-0.1.0/tests/fixtures/acp/goose-1.53.0/load-http-hangs.jsonl +16 -0
  118. acp_gateway-0.1.0/tests/fixtures/acp/goose-1.53.0/load-ws.jsonl +33 -0
  119. acp_gateway-0.1.0/tests/fixtures/acp/goose-1.53.0/modes.jsonl +8 -0
  120. acp_gateway-0.1.0/tests/fixtures/acp/goose-1.53.0/permission-reject.jsonl +23 -0
  121. acp_gateway-0.1.0/tests/fixtures/acp/goose-1.53.0/ping.jsonl +14 -0
  122. acp_gateway-0.1.0/tests/integration/test_agent_client.py +407 -0
  123. acp_gateway-0.1.0/tests/integration/test_agent_transport_factory.py +233 -0
  124. acp_gateway-0.1.0/tests/integration/test_agent_transport_robustness.py +234 -0
  125. acp_gateway-0.1.0/tests/integration/test_connector_control.py +504 -0
  126. acp_gateway-0.1.0/tests/integration/test_connector_multinode.py +431 -0
  127. acp_gateway-0.1.0/tests/integration/test_connector_process.py +196 -0
  128. acp_gateway-0.1.0/tests/integration/test_connector_relay.py +429 -0
  129. acp_gateway-0.1.0/tests/integration/test_daemon_cli.py +360 -0
  130. acp_gateway-0.1.0/tests/integration/test_gateway_approvals.py +172 -0
  131. acp_gateway-0.1.0/tests/integration/test_gateway_core.py +471 -0
  132. acp_gateway-0.1.0/tests/integration/test_hermes_compat.py +70 -0
  133. acp_gateway-0.1.0/tests/integration/test_mcp.py +147 -0
  134. acp_gateway-0.1.0/tests/integration/test_spike_against_fake_goose.py +177 -0
  135. acp_gateway-0.1.0/tests/integration/test_telegram.py +361 -0
  136. acp_gateway-0.1.0/tests/integration/test_tls_validity.py +41 -0
  137. acp_gateway-0.1.0/tests/integration/test_transport_redirects.py +38 -0
  138. acp_gateway-0.1.0/tests/unit/test_agent_client_safety.py +163 -0
  139. acp_gateway-0.1.0/tests/unit/test_approvals.py +289 -0
  140. acp_gateway-0.1.0/tests/unit/test_bus.py +84 -0
  141. acp_gateway-0.1.0/tests/unit/test_check_secrets.py +123 -0
  142. acp_gateway-0.1.0/tests/unit/test_cli.py +78 -0
  143. acp_gateway-0.1.0/tests/unit/test_cli_stream.py +81 -0
  144. acp_gateway-0.1.0/tests/unit/test_computer_diagnostics.py +53 -0
  145. acp_gateway-0.1.0/tests/unit/test_computers.py +166 -0
  146. acp_gateway-0.1.0/tests/unit/test_config.py +259 -0
  147. acp_gateway-0.1.0/tests/unit/test_connector_boundaries.py +106 -0
  148. acp_gateway-0.1.0/tests/unit/test_connector_commands.py +99 -0
  149. acp_gateway-0.1.0/tests/unit/test_connector_config.py +70 -0
  150. acp_gateway-0.1.0/tests/unit/test_connector_policy.py +442 -0
  151. acp_gateway-0.1.0/tests/unit/test_connector_protocol.py +130 -0
  152. acp_gateway-0.1.0/tests/unit/test_connector_service.py +172 -0
  153. acp_gateway-0.1.0/tests/unit/test_installation.py +170 -0
  154. acp_gateway-0.1.0/tests/unit/test_log.py +250 -0
  155. acp_gateway-0.1.0/tests/unit/test_maintenance_worker.py +130 -0
  156. acp_gateway-0.1.0/tests/unit/test_mcp_safety.py +81 -0
  157. acp_gateway-0.1.0/tests/unit/test_owner_api.py +236 -0
  158. acp_gateway-0.1.0/tests/unit/test_policy.py +29 -0
  159. acp_gateway-0.1.0/tests/unit/test_recorded_contract.py +78 -0
  160. acp_gateway-0.1.0/tests/unit/test_sanitize_fixture.py +56 -0
  161. acp_gateway-0.1.0/tests/unit/test_service.py +146 -0
  162. acp_gateway-0.1.0/tests/unit/test_service_env_literal.py +30 -0
  163. acp_gateway-0.1.0/tests/unit/test_storage.py +296 -0
  164. acp_gateway-0.1.0/tests/unit/test_tls_pin.py +97 -0
  165. acp_gateway-0.1.0/uv.lock +1857 -0
@@ -0,0 +1,9 @@
1
+ **
2
+ !pyproject.toml
3
+ !uv.lock
4
+ !README.md
5
+ !LICENSE
6
+ !src/
7
+ !src/**
8
+ src/**/__pycache__/
9
+ src/**/*.pyc
@@ -0,0 +1,12 @@
1
+ # Secrets only. Copy to .env (ignored by git), restrict access: chmod 600 .env
2
+ # Names are referenced from config.yaml (secret_env, api_token_env, mcp_token_env).
3
+
4
+ # Same value as GOOSE_SERVER__SECRET_KEY on the agent side
5
+ AGENT_WORK_SECRET=
6
+
7
+ # Bearer tokens for the local HTTP API and MCP endpoint
8
+ ACPGW_API_TOKEN=
9
+ ACPGW_MCP_TOKEN=
10
+
11
+ # Separate Telegram bot for the gateway
12
+ TELEGRAM_BOT_TOKEN=
@@ -0,0 +1,3 @@
1
+ * text=auto eol=lf
2
+ *.ps1 text eol=crlf
3
+ *.cmd text eol=crlf
@@ -0,0 +1,6 @@
1
+ #!/bin/sh
2
+ # Enabled with: git config core.hooksPath .githooks
3
+ set -e
4
+ uv run --frozen python scripts/check_secrets.py --staged
5
+ uv run --frozen ruff check
6
+ uv run --frozen ruff format --check
@@ -0,0 +1,105 @@
1
+ name: Platform release checks
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ publish_image:
7
+ description: 'Publish the tested Docker image to GHCR (manual release)'
8
+ required: false
9
+ type: boolean
10
+ default: false
11
+
12
+ permissions:
13
+ contents: read
14
+
15
+ jobs:
16
+ publish-image:
17
+ if: ${{ inputs.publish_image }}
18
+ needs: [build, native]
19
+ runs-on: ubuntu-22.04
20
+ timeout-minutes: 15
21
+ permissions:
22
+ contents: read
23
+ packages: write
24
+ steps:
25
+ - uses: actions/checkout@v4
26
+ with:
27
+ persist-credentials: false
28
+ - uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
29
+ with:
30
+ python-version: '3.12'
31
+ - run: uv sync --frozen
32
+ - name: Select versioned image
33
+ run: |
34
+ release_version=$(uv run --frozen python -c 'from acp_gateway import __version__; print(__version__)')
35
+ echo "ACPGW_RELEASE_IMAGE=ghcr.io/${GITHUB_REPOSITORY,,}:$release_version" >> "$GITHUB_ENV"
36
+ - run: docker build -t "$ACPGW_RELEASE_IMAGE" .
37
+ - run: uv run --frozen python scripts/smoke_docker.py --image "$ACPGW_RELEASE_IMAGE"
38
+ - name: Publish tested image
39
+ env:
40
+ GHCR_TOKEN: ${{ secrets.GITHUB_TOKEN }}
41
+ run: |
42
+ printf '%s' "$GHCR_TOKEN" | docker login ghcr.io --username "$GITHUB_ACTOR" --password-stdin
43
+ if docker manifest inspect "$ACPGW_RELEASE_IMAGE" >/dev/null 2>&1; then
44
+ echo 'Version tag already exists; increment the package version instead of replacing it.' >&2
45
+ exit 1
46
+ fi
47
+ docker push "$ACPGW_RELEASE_IMAGE"
48
+ - name: Clear registry credentials
49
+ if: ${{ always() }}
50
+ run: docker logout ghcr.io
51
+ native:
52
+ strategy:
53
+ fail-fast: false
54
+ matrix:
55
+ runner: [windows-2025, macos-15, macos-15-intel, ubuntu-24.04-arm]
56
+ runs-on: ${{ matrix.runner }}
57
+ timeout-minutes: 25
58
+ steps:
59
+ - uses: actions/checkout@v4
60
+ with:
61
+ persist-credentials: false
62
+ - uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
63
+ with:
64
+ python-version: '3.12'
65
+ - run: uv sync --frozen --group build
66
+ - run: uv build --wheel --out-dir dist/native
67
+ - run: uv run --frozen --group build python scripts/build_binary.py
68
+ - run: uv run --frozen python scripts/smoke_platform.py --wheel-dir dist/native --built-binary
69
+ - uses: actions/upload-artifact@v4
70
+ with:
71
+ name: acpgw-${{ matrix.runner }}
72
+ path: |
73
+ dist/*.tar.gz
74
+ dist/*.sha256
75
+ dist/*.build.json
76
+ if-no-files-found: error
77
+ build:
78
+ runs-on: ubuntu-22.04
79
+ timeout-minutes: 20
80
+ steps:
81
+ - uses: actions/checkout@v4
82
+ with:
83
+ persist-credentials: false
84
+ - uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0
85
+ with:
86
+ python-version: '3.12'
87
+ - run: uv sync --frozen --group build
88
+ - run: uv run --frozen ruff check
89
+ - run: uv run --frozen ruff format --check
90
+ - run: uv run --frozen pytest
91
+ - run: uv run --frozen --group build python scripts/build_binary.py
92
+ - run: uv run --frozen python scripts/smoke_binary.py dist/acpgw-linux-x86_64/acpgw
93
+ - run: uv run --frozen python scripts/smoke_connector.py dist/acpgw-linux-x86_64/acpgw
94
+ - name: Check executable in Ubuntu without Python
95
+ run: >-
96
+ uv run --frozen python scripts/smoke_binary.py
97
+ dist/acpgw-linux-x86_64/acpgw --container-image ubuntu:22.04
98
+ - uses: actions/upload-artifact@v4
99
+ with:
100
+ name: acpgw-linux-x86_64
101
+ path: |
102
+ dist/*.tar.gz
103
+ dist/*.sha256
104
+ dist/*.build.json
105
+ if-no-files-found: error
@@ -0,0 +1,40 @@
1
+ # Secrets — never commit
2
+ .env
3
+ .env.*
4
+ !.env.example
5
+ config.yaml
6
+ *.pem
7
+ *.key
8
+
9
+ # Runtime data
10
+ data/
11
+ *.db
12
+ *.db-journal
13
+ *.db-wal
14
+ *.db-shm
15
+ *.log
16
+
17
+ # Python
18
+ __pycache__/
19
+ *.py[cod]
20
+ .venv/
21
+ build/
22
+ dist/
23
+ *.egg-info/
24
+ .pytest_cache/
25
+ .ruff_cache/
26
+ .coverage
27
+ htmlcov/
28
+
29
+ # Editors / OS
30
+ .idea/
31
+ .vscode/
32
+ .DS_Store
33
+ Thumbs.db
34
+
35
+ # ACP spike output (may contain work data)
36
+ spike-runs/
37
+
38
+ # Private VPS deployment configuration, credentials and persistent state
39
+ deploy/docker/runtime/
40
+ deploy/docker/state/
@@ -0,0 +1 @@
1
+ 3.12
@@ -0,0 +1,19 @@
1
+ FROM ghcr.io/astral-sh/uv:0.7.6 AS uv
2
+ FROM python:3.12-slim-bookworm AS build
3
+ COPY --from=uv /uv /usr/local/bin/uv
4
+ WORKDIR /app
5
+ ENV UV_LINK_MODE=copy UV_PYTHON_DOWNLOADS=never
6
+ COPY pyproject.toml uv.lock README.md LICENSE ./
7
+ COPY src ./src
8
+ RUN uv sync --frozen --no-dev --no-editable
9
+
10
+ FROM python:3.12-slim-bookworm AS runtime
11
+ RUN groupadd --gid 10001 acpgw && useradd --uid 10001 --gid acpgw --create-home acpgw \
12
+ && mkdir /data /config && chown acpgw:acpgw /data /config
13
+ COPY --from=build /app/.venv /app/.venv
14
+ ENV PATH=/app/.venv/bin:$PATH PYTHONUNBUFFERED=1 PYTHONDONTWRITEBYTECODE=1 \
15
+ XDG_DATA_HOME=/data
16
+ USER 10001:10001
17
+ WORKDIR /data
18
+ ENTRYPOINT ["acpgw", "--config", "/config/gateway.yaml", "--env-file", "/config/gateway.env"]
19
+ CMD ["serve"]
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Lujker
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,309 @@
1
+ Metadata-Version: 2.5
2
+ Name: acp-gateway
3
+ Version: 0.1.0
4
+ Summary: Local gateway that routes messages from external channels (Hermes, Telegram, ...) to ACP agents
5
+ Project-URL: Homepage, https://github.com/Lujker/acp-gateway
6
+ Project-URL: Repository, https://github.com/Lujker/acp-gateway
7
+ Project-URL: Issues, https://github.com/Lujker/acp-gateway/issues
8
+ Author: Lujker
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: acp,agent-client-protocol,gateway,goose,hermes,mcp,telegram
12
+ Classifier: Development Status :: 2 - Pre-Alpha
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: POSIX :: Linux
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Communications :: Chat
19
+ Classifier: Topic :: Software Development
20
+ Requires-Python: >=3.12
21
+ Requires-Dist: agent-client-protocol[http]>=0.12
22
+ Requires-Dist: aiogram<4,>=3.22
23
+ Requires-Dist: fastapi>=0.115
24
+ Requires-Dist: filelock>=3.16
25
+ Requires-Dist: httpx>=0.28
26
+ Requires-Dist: mcp<2,>=1.20
27
+ Requires-Dist: packaging>=24
28
+ Requires-Dist: platformdirs>=4.3
29
+ Requires-Dist: pydantic-settings[yaml]>=2.8
30
+ Requires-Dist: pydantic>=2.10
31
+ Requires-Dist: python-dotenv>=1.0
32
+ Requires-Dist: structlog>=25.1
33
+ Requires-Dist: uvicorn>=0.34
34
+ Requires-Dist: websockets>=15
35
+ Description-Content-Type: text/markdown
36
+
37
+ # ACP Gateway
38
+
39
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
40
+ ![Python 3.12+](https://img.shields.io/badge/python-3.12%2B-blue.svg)
41
+ ![Status: early development](https://img.shields.io/badge/status-early%20development-orange.svg)
42
+ [![ACP](https://img.shields.io/badge/protocol-Agent%20Client%20Protocol-6f42c1.svg)](https://agentclientprotocol.com)
43
+
44
+ **ACP Gateway** is a local gateway that lets chat channels and other agents —
45
+ Hermes, Telegram, later XMPP, e-mail and a web UI — talk to a remote
46
+ [Agent Client Protocol](https://agentclientprotocol.com) agent such as
47
+ [goose](https://github.com/aaif-goose/goose). It delivers messages to the
48
+ agent and returns answers and tool-approval requests to the channels, with a
49
+ human in the loop for every risky action.
50
+
51
+ The first target is **Work Goose**: `goose serve` on a work laptop. Work MCP
52
+ servers, credentials, files and the model stay on that machine; the gateway
53
+ only knows the agent's address, a shared secret and the fingerprint of its TLS
54
+ certificate.
55
+
56
+ ```mermaid
57
+ flowchart LR
58
+ subgraph home["Home host (WSL)"]
59
+ hermes["Hermes"] -- MCP --> gw
60
+ tg["Telegram"] --> gw
61
+ cli["CLI / Web UI"] -- HTTP --> gw
62
+ gw["ACP Gateway<br/>sessions · approvals · policy · audit"]
63
+ end
64
+ subgraph work["Work laptop (WSL)"]
65
+ goose["goose serve<br/>MCP · files · model"]
66
+ end
67
+ gw -- "ACP over WebSocket<br/>TLS pinning + X-Secret-Key" --> goose
68
+ desktop["Goose Desktop"] -. direct .-> goose
69
+ ```
70
+
71
+ ## Status
72
+
73
+ Early development. The foundation is done: the connection to a real goose
74
+ 1.53.0 over the LAN is verified, along with sessions, approvals, cancellation
75
+ and session restore. The daemon, local HTTP/SSE API and human CLI channel are
76
+ implemented and verified against Work Goose. The Hermes MCP facade is implemented
77
+ and checked with Hermes' installed MCP module against the recorded Goose mock.
78
+ Linux/WSL service lifecycle and Telegram commands/approval buttons are implemented;
79
+ actual reboot and the live human Telegram acceptance remain pending. Connector
80
+ development includes local computer enrollment and a guarded WS/WSS ACP relay
81
+ in `serve`, tested against the recorded agent mock. Live acceptance is next. The plan
82
+ and the work queue are in [`road-map.md`](road-map.md) (in Russian).
83
+
84
+ | Area | State |
85
+ |---|---|
86
+ | Scaffold, config, secret redaction, pre-commit hook | ✅ |
87
+ | ACP over WebSocket with TLS pinning, verified on goose 1.53.0 | ✅ |
88
+ | Agent client (`acp_gateway.agents`) and recorded-traffic mock agent | ✅ `P1.1`, `P1.2` |
89
+ | Core: sessions in SQLite, jobs, event bus, channel contract | ✅ `P1.3` |
90
+ | Approvals: human routing, deadlines, audit; core policy limits | ✅ `P1.4` |
91
+ | Daemon, local API, approvals from the CLI | ✅ `P1.5` |
92
+ | Hermes MCP facade; actions approved through the CLI | ✅ `P2.1`, `P2.2` (Hermes MCP module + mock agent) |
93
+ | Checkout installer, setup, Linux/WSL service CLI, standalone Linux binary recipe | Binary, real user-service/crash recovery and Windows task lifecycle verified; actual reboot pending |
94
+ | Telegram | Commands, private user allowlist and audited approval buttons implemented; live acceptance pending |
95
+ | Runtime diagnostics | Component health/probes, private rotated JSON logs and Telegram throttling/recovery implemented |
96
+ | [VPS connector](docs/items/connector.md) | ACP relay, Linux/WSL services and route diagnostics implemented; two-computer isolation/approvals/history mock-tested; live acceptance next |
97
+ | Snikket/XMPP, e-mail, web UI | 🗓 `P4` |
98
+
99
+ ## Principles
100
+
101
+ - **The agent executes, the gateway relays.** The gateway makes no decisions
102
+ for the agent and stores no work MCP credentials.
103
+ - **A human approves.** Agent actions are approved in a channel with a live
104
+ human (CLI, Telegram). LLM channels, Hermes included, never get an "allow"
105
+ button. With no approver connected, the action is rejected.
106
+ - **Secure by default.** The local API listens on loopback only. Unencrypted
107
+ transport to an agent is allowed only on loopback. The secret is sent only
108
+ after the pinned certificate is verified. ACP client capabilities (`fs`,
109
+ `terminal`) are disabled. Secrets are masked in logs and kept out of git.
110
+ - **Channels are thin adapters.** A new channel implements a shared contract
111
+ and does not touch the core.
112
+
113
+ More in [`docs/architecture.md`](docs/architecture.md).
114
+
115
+ ## Quick start
116
+
117
+ For a VPS in Docker, two outgoing Linux/WSL connectors and Telegram, follow
118
+ the [live acceptance runbook](docs/setup/vps-acceptance.md)
119
+ ([на русском](docs/setup/vps-acceptance.ru.md)). It starts with
120
+ an IP/port route and then adds an exact WSS path through its own nginx without
121
+ publishing the owner API or changing other application services.
122
+
123
+ For installation without a checkout, use the wheel/deployment bundle described
124
+ in [installation and updates](docs/setup/distribution.md). Public PyPI/registry
125
+ publication is a separate manual release step. Internal maintenance commands
126
+ for uv installations are `acpgw version`, `update`, `update --status`,
127
+ `update --rollback` and `uninstall`. Updates take a private recovery snapshot
128
+ and restore it on installation/health-check failure. Native Windows queues
129
+ internal maintenance after the CLI exits; its PowerShell installer waits for
130
+ the verified result. See the installation guide before rolling back a database.
131
+
132
+ For the separate Git/development path, you need [uv](https://docs.astral.sh/uv/) and git; uv installs Python 3.12
133
+ itself. Linux/WSL is the primary platform. Native Windows x86_64, macOS Intel/ARM64
134
+ and Linux ARM64 have wheel lifecycle and binary CLI checks; native Windows/macOS
135
+ services and full agent acceptance remain separate milestones.
136
+
137
+ ```bash
138
+ git clone --branch v0.1.0 https://github.com/Lujker/acp-gateway.git
139
+ cd acp-gateway
140
+ uv sync --frozen
141
+ ```
142
+
143
+ For an installed `acpgw` command outside the checkout, run
144
+ `sh scripts/install.sh`, then configure the files created by `acpgw setup`.
145
+ The installer keeps existing configuration and tokens. Installation and
146
+ service commands: [`docs/setup/service.md`](docs/setup/service.md).
147
+
148
+ Use a published, reviewed tag as above; before the first release, select the
149
+ reviewed branch or commit explicitly. For development, create a working branch
150
+ from that checkout.
151
+
152
+ To build a standalone executable with no Python required on the runtime
153
+ host, use `uv run --frozen --group build python scripts/build_binary.py`.
154
+ Build artifacts, checksums, compatibility limits and installation:
155
+ [`docs/setup/binary.md`](docs/setup/binary.md).
156
+ Build locally and attach archives/checksums to a manually created GitHub
157
+ release. The optional GitHub Actions build runs only on explicit manual
158
+ dispatch; pushes, PRs, tags and releases do not consume build minutes.
159
+
160
+ Telegram setup and human approvals: [`docs/setup/telegram.md`](docs/setup/telegram.md).
161
+ Health probes and rotating logs: [`docs/setup/observability.md`](docs/setup/observability.md).
162
+
163
+ ### 1. Prepare the agent
164
+
165
+ On the agent machine, run `goose serve` with TLS and a secret and open the
166
+ port to the LAN. Step by step, including the Hyper-V firewall rule for WSL:
167
+ [`docs/setup/work-goose.md`](docs/setup/work-goose.md).
168
+
169
+ ```bash
170
+ GOOSE_SERVER__SECRET_KEY='<long random secret>' \
171
+ goose serve --host 0.0.0.0 --port 3284 --tls
172
+ # note the GOOSED_CERT_FINGERPRINT=... line
173
+ ```
174
+
175
+ ### 2. Configure the gateway
176
+
177
+ ```bash
178
+ cp config.example.yaml config.yaml # agents, policy, logging
179
+ cp .env.example .env && chmod 600 .env # secrets only
180
+ ```
181
+
182
+ Set the agent address and certificate fingerprint in `config.yaml`:
183
+
184
+ ```yaml
185
+ agents:
186
+ - alias: work
187
+ title: Work Goose
188
+ kind: goose
189
+ url: https://<agent-address>:3284 # /acp is appended automatically
190
+ secret_env: AGENT_WORK_SECRET
191
+ tls_fingerprint: "<GOOSED_CERT_FINGERPRINT>" # empty = trust on first use
192
+ default_cwd: /home/<user>
193
+ ```
194
+
195
+ In `.env`: `AGENT_WORK_SECRET=<the same secret>`.
196
+ Also set `ACPGW_API_TOKEN` to a separate random owner token. It must differ
197
+ from the agent secret and `ACPGW_MCP_TOKEN` (if configured).
198
+
199
+ ### 3. Check the connection
200
+
201
+ ```bash
202
+ uv run acpgw config check # config is valid, secrets are present
203
+ uv run python scripts/spike_acp.py init # TLS + ACP handshake
204
+ uv run python scripts/spike_acp.py ping # a short request to the agent
205
+ ```
206
+
207
+ The spike script has more scenarios: `modes`, `permission`, `cancel`, `load`,
208
+ `all`. Traffic is recorded to `spike-runs/` (git-ignored). The scenarios
209
+ `permission --permission allow` and `cancel` run harmless `echo` and `sleep`
210
+ commands on the agent machine.
211
+
212
+ ### 4. Start the daemon and use the CLI
213
+
214
+ ```bash
215
+ uv run acpgw serve # keep this terminal open
216
+ ```
217
+
218
+ In another terminal:
219
+
220
+ ```bash
221
+ uv run acpgw status
222
+ uv run acpgw ask "Remember the code word AMBER. Answer only OK."
223
+ uv run acpgw ask "What was the code word?" # same active session
224
+ uv run acpgw sessions
225
+ uv run acpgw new # start a fresh session
226
+ uv run acpgw switch 1 # gateway session row id from sessions
227
+ ```
228
+
229
+ For actions that need approval, keep a third terminal connected:
230
+
231
+ ```bash
232
+ uv run acpgw approvals watch # allow once, reject, or skip interactively
233
+ ```
234
+
235
+ The daemon alone does not count as a connected human. With no approval
236
+ watcher, requests are rejected. `acpgw approvals` lists pending requests;
237
+ `acpgw approvals approve <id>` and `reject <id>` decide an existing request
238
+ once. Long jobs can be submitted with `ask --no-stream`, retrieved with
239
+ `result <job_id> --wait 30`, and cancelled with `stop`. Ctrl+C during a
240
+ streaming `ask` requests cancellation of that job.
241
+
242
+ The CLI reads the same config and secrets as the daemon. Details and the
243
+ HTTP/SSE contract: [`docs/setup/gateway.md`](docs/setup/gateway.md).
244
+
245
+ ### 5. Connect Hermes
246
+
247
+ Set a separate `ACPGW_MCP_TOKEN`, restart the daemon and add its `/mcp` URL
248
+ and bearer header to Hermes' `mcp_servers`. The six tools for each agent
249
+ support sessions, explicit threads, asynchronous jobs and cancellation.
250
+ Actions still require a human in `acpgw approvals watch`.
251
+ Configuration, tool arguments and compatibility checks:
252
+ [`docs/setup/hermes.md`](docs/setup/hermes.md).
253
+
254
+ ### 6. Manage autostart on Linux/WSL
255
+
256
+ ```bash
257
+ acpgw service install # install/update the user unit using the selected config
258
+ acpgw service enable # enable autostart and start now
259
+ acpgw service status # service state, including when the daemon is stopped
260
+ acpgw service disable # disable autostart and stop now
261
+ acpgw service --help # start, stop, restart and uninstall too
262
+ ```
263
+
264
+ WSL also needs a Windows logon task and a user manager that starts with the
265
+ distro. Instructions and the remaining reboot check:
266
+ [`docs/setup/service.md`](docs/setup/service.md).
267
+
268
+ ## Configuration
269
+
270
+ | Source | Contents |
271
+ |---|---|
272
+ | `config.yaml` (`--config`, `ACPGW_CONFIG`, `./`, platform config dir) | structure: `gateway`, `agents`, `policy`, `logging` |
273
+ | `ACPGW_<SECTION>__<FIELD>` variables | overrides, e.g. `ACPGW_LOGGING__LEVEL=DEBUG` |
274
+ | `.env` (`--env-file`, `ACPGW_ENV_FILE`, `./`, config dir) | **secrets only**, referenced by name (`secret_env`) |
275
+
276
+ `uv run acpgw paths` shows the config, data and log directories on the
277
+ current platform.
278
+
279
+ ## Development
280
+
281
+ ```bash
282
+ uv sync # environment and dependencies
283
+ git config core.hooksPath .githooks # pre-commit: secret scan + ruff
284
+ uv run pytest # unit + integration tests
285
+ uv run ruff check && uv run ruff format --check
286
+ ```
287
+
288
+ Integration tests start a mock goose (`tests/fakes/fake_goose.py`) whose
289
+ messages come from real goose 1.53.0 recordings in `tests/fixtures/acp/`; it
290
+ covers TLS, the secret, session modes, approvals, cancellation, session
291
+ loading and restarts. New recordings are cleaned with
292
+ `scripts/sanitize_fixture.py` before committing.
293
+
294
+ The development plan lives in [`road-map.md`](road-map.md) (statuses and
295
+ queue) and [`road-notes.md`](road-notes.md) (decisions and findings); both are
296
+ kept in Russian.
297
+
298
+ ## Layout
299
+
300
+ ```text
301
+ src/acp_gateway/ ACP client, core, SQLite storage, daemon, HTTP/SSE API, CLI, channels
302
+ scripts/ spike_acp.py (agent check), check_secrets.py (hook), sanitize_fixture.py
303
+ tests/ unit, integration, fakes, fixtures/acp
304
+ docs/ architecture.md, setup/, archive/
305
+ ```
306
+
307
+ ## License
308
+
309
+ [MIT](LICENSE)