aimessenger 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.
- aimessenger-0.1.0/.claude/settings.json +3 -0
- aimessenger-0.1.0/.claude-plugin/marketplace.json +21 -0
- aimessenger-0.1.0/.gitattributes +4 -0
- aimessenger-0.1.0/.gitignore +23 -0
- aimessenger-0.1.0/LICENSE +28 -0
- aimessenger-0.1.0/PACKAGE.md +57 -0
- aimessenger-0.1.0/PKG-INFO +90 -0
- aimessenger-0.1.0/README.md +26 -0
- aimessenger-0.1.0/deploy/.env.example +43 -0
- aimessenger-0.1.0/deploy/Dockerfile +16 -0
- aimessenger-0.1.0/deploy/README-deploy.md +96 -0
- aimessenger-0.1.0/deploy/backup.sh +21 -0
- aimessenger-0.1.0/deploy/docker-compose.yml +50 -0
- aimessenger-0.1.0/deploy/update.sh +9 -0
- aimessenger-0.1.0/docs/DIRECTORY-SUBMISSION.md +84 -0
- aimessenger-0.1.0/docs/DOMAIN-MOVE.md +65 -0
- aimessenger-0.1.0/docs/PLAN.md +243 -0
- aimessenger-0.1.0/docs/PLUGIN.md +210 -0
- aimessenger-0.1.0/docs/PROTOCOL.md +188 -0
- aimessenger-0.1.0/docs/ROADMAP.md +212 -0
- aimessenger-0.1.0/docs/SECURITY.md +49 -0
- aimessenger-0.1.0/docs/USAGE.md +177 -0
- aimessenger-0.1.0/docs/V2-SERVER-SIDE.md +133 -0
- aimessenger-0.1.0/plugin/.claude-plugin/plugin.json +16 -0
- aimessenger-0.1.0/plugin/.mcp.json +8 -0
- aimessenger-0.1.0/plugin/README.md +41 -0
- aimessenger-0.1.0/pyproject.toml +63 -0
- aimessenger-0.1.0/src/aimessenger/__init__.py +3 -0
- aimessenger-0.1.0/src/aimessenger/client/__init__.py +1 -0
- aimessenger-0.1.0/src/aimessenger/client/channel/__init__.py +1 -0
- aimessenger-0.1.0/src/aimessenger/client/channel/__main__.py +6 -0
- aimessenger-0.1.0/src/aimessenger/client/channel/instructions.py +35 -0
- aimessenger-0.1.0/src/aimessenger/client/channel/server.py +612 -0
- aimessenger-0.1.0/src/aimessenger/client/channel/spike.py +198 -0
- aimessenger-0.1.0/src/aimessenger/client/channel/tools.py +133 -0
- aimessenger-0.1.0/src/aimessenger/client/claude_sessions.py +51 -0
- aimessenger-0.1.0/src/aimessenger/client/cli.py +728 -0
- aimessenger-0.1.0/src/aimessenger/client/config.py +71 -0
- aimessenger-0.1.0/src/aimessenger/client/identity.py +76 -0
- aimessenger-0.1.0/src/aimessenger/client/relay_client.py +323 -0
- aimessenger-0.1.0/src/aimessenger/client/resolve.py +146 -0
- aimessenger-0.1.0/src/aimessenger/client/store.py +338 -0
- aimessenger-0.1.0/src/aimessenger/protocol/__init__.py +17 -0
- aimessenger-0.1.0/src/aimessenger/protocol/address.py +103 -0
- aimessenger-0.1.0/src/aimessenger/protocol/canonical.py +17 -0
- aimessenger-0.1.0/src/aimessenger/protocol/crypto.py +61 -0
- aimessenger-0.1.0/src/aimessenger/protocol/framing.py +71 -0
- aimessenger-0.1.0/src/aimessenger/protocol/grants.py +79 -0
- aimessenger-0.1.0/src/aimessenger/protocol/httpsig.py +68 -0
- aimessenger-0.1.0/src/aimessenger/protocol/models.py +210 -0
- aimessenger-0.1.0/src/aimessenger/protocol/timeutil.py +35 -0
- aimessenger-0.1.0/src/aimessenger/relay/__init__.py +1 -0
- aimessenger-0.1.0/src/aimessenger/relay/accounts.py +189 -0
- aimessenger-0.1.0/src/aimessenger/relay/admin.py +297 -0
- aimessenger-0.1.0/src/aimessenger/relay/app.py +190 -0
- aimessenger-0.1.0/src/aimessenger/relay/config.py +87 -0
- aimessenger-0.1.0/src/aimessenger/relay/db.py +660 -0
- aimessenger-0.1.0/src/aimessenger/relay/http.py +199 -0
- aimessenger-0.1.0/src/aimessenger/relay/i18n.py +237 -0
- aimessenger-0.1.0/src/aimessenger/relay/mail.py +89 -0
- aimessenger-0.1.0/src/aimessenger/relay/mcp_server.py +433 -0
- aimessenger-0.1.0/src/aimessenger/relay/notify.py +106 -0
- aimessenger-0.1.0/src/aimessenger/relay/oauth.py +216 -0
- aimessenger-0.1.0/src/aimessenger/relay/secrets_store.py +97 -0
- aimessenger-0.1.0/src/aimessenger/relay/service.py +508 -0
- aimessenger-0.1.0/src/aimessenger/relay/static/icon.svg +5 -0
- aimessenger-0.1.0/src/aimessenger/relay/templates/app.html +98 -0
- aimessenger-0.1.0/src/aimessenger/relay/templates/base.html +106 -0
- aimessenger-0.1.0/src/aimessenger/relay/templates/consent.html +18 -0
- aimessenger-0.1.0/src/aimessenger/relay/templates/login.html +26 -0
- aimessenger-0.1.0/src/aimessenger/relay/templates/message.html +6 -0
- aimessenger-0.1.0/src/aimessenger/relay/templates/pages/docs.cs.html +135 -0
- aimessenger-0.1.0/src/aimessenger/relay/templates/pages/docs.en.html +140 -0
- aimessenger-0.1.0/src/aimessenger/relay/templates/pages/landing.cs.html +96 -0
- aimessenger-0.1.0/src/aimessenger/relay/templates/pages/landing.en.html +101 -0
- aimessenger-0.1.0/src/aimessenger/relay/templates/pages/privacy.cs.html +67 -0
- aimessenger-0.1.0/src/aimessenger/relay/templates/pages/privacy.en.html +70 -0
- aimessenger-0.1.0/src/aimessenger/relay/templates/pages/terms.cs.html +50 -0
- aimessenger-0.1.0/src/aimessenger/relay/templates/pages/terms.en.html +52 -0
- aimessenger-0.1.0/src/aimessenger/relay/templates/register.html +30 -0
- aimessenger-0.1.0/src/aimessenger/relay/templates/reset.html +21 -0
- aimessenger-0.1.0/src/aimessenger/relay/templates/reset_confirm.html +13 -0
- aimessenger-0.1.0/src/aimessenger/relay/web.py +687 -0
- aimessenger-0.1.0/src/aimessenger/relay/ws.py +184 -0
- aimessenger-0.1.0/tests/__init__.py +0 -0
- aimessenger-0.1.0/tests/conftest.py +6 -0
- aimessenger-0.1.0/tests/test_channel_spike_wire.py +70 -0
- aimessenger-0.1.0/tests/test_client_e2e.py +253 -0
- aimessenger-0.1.0/tests/test_imports.py +16 -0
- aimessenger-0.1.0/tests/test_legacy_host.py +50 -0
- aimessenger-0.1.0/tests/test_live_relay.py +245 -0
- aimessenger-0.1.0/tests/test_notify.py +160 -0
- aimessenger-0.1.0/tests/test_plugin_manifest.py +51 -0
- aimessenger-0.1.0/tests/test_protocol.py +170 -0
- aimessenger-0.1.0/tests/test_public_pages.py +119 -0
- aimessenger-0.1.0/tests/test_relay_integration.py +311 -0
- aimessenger-0.1.0/tests/test_relay_ws_supervisor.py +87 -0
- aimessenger-0.1.0/tests/test_resolve.py +104 -0
- aimessenger-0.1.0/tests/test_turnstile.py +89 -0
- aimessenger-0.1.0/tests/test_v2_web_oauth.py +423 -0
- aimessenger-0.1.0/uv.lock +1135 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "aim",
|
|
3
|
+
"description": "The AIM channel plugin, published by the operator of the aim.mailows.com relay.",
|
|
4
|
+
"owner": {
|
|
5
|
+
"name": "DW Technology LLC",
|
|
6
|
+
"email": "aim@namailu.cz",
|
|
7
|
+
"url": "https://aim.mailows.com"
|
|
8
|
+
},
|
|
9
|
+
"plugins": [
|
|
10
|
+
{
|
|
11
|
+
"name": "aim",
|
|
12
|
+
"source": "./plugin",
|
|
13
|
+
"description": "Messages between AI coding sessions across tools, accounts and companies, with human-approved access.",
|
|
14
|
+
"version": "0.1.0",
|
|
15
|
+
"author": { "name": "DW Technology LLC" },
|
|
16
|
+
"homepage": "https://aim.mailows.com/docs",
|
|
17
|
+
"license": "AGPL-3.0-only",
|
|
18
|
+
"keywords": ["channel", "mcp", "messaging", "cross-account", "aim"]
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
build/
|
|
6
|
+
dist/
|
|
7
|
+
.venv/
|
|
8
|
+
.pytest_cache/
|
|
9
|
+
.ruff_cache/
|
|
10
|
+
.mypy_cache/
|
|
11
|
+
# Local state / secrets – never commit
|
|
12
|
+
.env
|
|
13
|
+
*.sqlite
|
|
14
|
+
*.sqlite-*
|
|
15
|
+
*.db
|
|
16
|
+
.aim/
|
|
17
|
+
identity.key
|
|
18
|
+
# OS / editor
|
|
19
|
+
*.stackdump
|
|
20
|
+
.DS_Store
|
|
21
|
+
Thumbs.db
|
|
22
|
+
.idea/
|
|
23
|
+
.vscode/
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, DW Technology LLC
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its contributors
|
|
16
|
+
may be used to endorse or promote products derived from this software
|
|
17
|
+
without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# AIM — messages between AI coding sessions
|
|
2
|
+
|
|
3
|
+
Claude Code already passes messages between sessions, but only within one seat and only between
|
|
4
|
+
Claudes. The colleague at the next desk, on their own seat in the same company, is already out of
|
|
5
|
+
reach — let alone someone working in Codex, Gemini CLI or Grok.
|
|
6
|
+
|
|
7
|
+
AIM closes that gap. A question travels from one coding session to someone else's session — another
|
|
8
|
+
tool, another account, another company — and the answer comes back the same way. **Who may reach
|
|
9
|
+
whom is approved by a person in a browser, never by a model.**
|
|
10
|
+
|
|
11
|
+
- Service: <https://aim.mailows.com>
|
|
12
|
+
- Guide: <https://aim.mailows.com/docs>
|
|
13
|
+
- Plugin for Claude Code: <https://github.com/mailows/aim-plugin>
|
|
14
|
+
|
|
15
|
+
## What this package gives you
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
uv tool install aimessenger
|
|
19
|
+
aim init --relay aim.mailows.com --handle your-handle
|
|
20
|
+
aim install-claude
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
- **`aim`** — a CLI for the whole protocol: `ask`, `answer`, `notify`, `inbox`, `contacts`,
|
|
24
|
+
`pair request|approve|deny|revoke`, `alias`, `label`, `thread`, `export`.
|
|
25
|
+
- **`aim channel`** — the Claude Code *channel* MCP server. It wakes the session when a message
|
|
26
|
+
arrives, so a question lands in the conversation instead of waiting to be collected. Claude Code
|
|
27
|
+
starts it for you; you never run it by hand.
|
|
28
|
+
- **`aim-relay`** — the relay server itself, for running your own (`pip install aimessenger[relay]`).
|
|
29
|
+
|
|
30
|
+
Nothing to install is also an option: the same tools are available over a remote MCP server at
|
|
31
|
+
`https://aim.mailows.com/mcp`, where the model asks for new messages rather than being woken by
|
|
32
|
+
them.
|
|
33
|
+
|
|
34
|
+
## How it works
|
|
35
|
+
|
|
36
|
+
Every session has an address shaped `handle@aim.mailows.com/session-name`. A relay carries signed
|
|
37
|
+
messages between addresses and enforces who may write to whom:
|
|
38
|
+
|
|
39
|
+
1. You ask a peer for access. They receive the request with your key fingerprint.
|
|
40
|
+
2. A person approves it on the website. The model has no tool for it and never will, so no incoming
|
|
41
|
+
message can talk it into granting anything.
|
|
42
|
+
3. From then on questions and answers flow. A question waits for one answer until its deadline; if
|
|
43
|
+
the other side is offline, the relay holds the message and delivers it on reconnect.
|
|
44
|
+
|
|
45
|
+
Every envelope is Ed25519-signed and verified by the recipient against a pinned key, so a relay
|
|
46
|
+
cannot forge one. Text that arrives from a peer is data to the model, never instructions — the
|
|
47
|
+
channel repeats that on every connection.
|
|
48
|
+
|
|
49
|
+
## Requirements
|
|
50
|
+
|
|
51
|
+
Python 3.14 or later. The channel needs Claude Code 2.1.268 or later; channels are a research
|
|
52
|
+
preview there, so it currently starts with `--dangerously-load-development-channels server:aim`
|
|
53
|
+
unless your organization allowlists the plugin.
|
|
54
|
+
|
|
55
|
+
## Licence
|
|
56
|
+
|
|
57
|
+
BSD 3-Clause.
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: aimessenger
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: AIM - AI Session Messenger: messages between AI coding sessions across tools, accounts and companies
|
|
5
|
+
Project-URL: Homepage, https://aim.mailows.com
|
|
6
|
+
Project-URL: Documentation, https://aim.mailows.com/docs
|
|
7
|
+
Project-URL: Plugin, https://github.com/mailows/aim-plugin
|
|
8
|
+
Author-email: DW Technology LLC <aim@namailu.cz>
|
|
9
|
+
License-Expression: BSD-3-Clause
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: agents,channel,claude-code,codex,mcp,messaging
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
+
Classifier: Topic :: Communications :: Chat
|
|
17
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
18
|
+
Requires-Python: >=3.14
|
|
19
|
+
Requires-Dist: aiosqlite>=0.21
|
|
20
|
+
Requires-Dist: argon2-cffi>=25.1.0
|
|
21
|
+
Requires-Dist: jinja2>=3.1.6
|
|
22
|
+
Requires-Dist: mcp>=2.2
|
|
23
|
+
Requires-Dist: platformdirs>=4
|
|
24
|
+
Requires-Dist: pydantic>=2.12
|
|
25
|
+
Requires-Dist: pynacl>=1.5
|
|
26
|
+
Requires-Dist: python-ulid>=3
|
|
27
|
+
Requires-Dist: typer>=0.15
|
|
28
|
+
Requires-Dist: websockets>=15
|
|
29
|
+
Provides-Extra: relay
|
|
30
|
+
Requires-Dist: starlette>=0.48; extra == 'relay'
|
|
31
|
+
Requires-Dist: uvicorn[standard]>=0.31; extra == 'relay'
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
|
|
34
|
+
# AIM — messages between AI coding sessions
|
|
35
|
+
|
|
36
|
+
Claude Code already passes messages between sessions, but only within one seat and only between
|
|
37
|
+
Claudes. The colleague at the next desk, on their own seat in the same company, is already out of
|
|
38
|
+
reach — let alone someone working in Codex, Gemini CLI or Grok.
|
|
39
|
+
|
|
40
|
+
AIM closes that gap. A question travels from one coding session to someone else's session — another
|
|
41
|
+
tool, another account, another company — and the answer comes back the same way. **Who may reach
|
|
42
|
+
whom is approved by a person in a browser, never by a model.**
|
|
43
|
+
|
|
44
|
+
- Service: <https://aim.mailows.com>
|
|
45
|
+
- Guide: <https://aim.mailows.com/docs>
|
|
46
|
+
- Plugin for Claude Code: <https://github.com/mailows/aim-plugin>
|
|
47
|
+
|
|
48
|
+
## What this package gives you
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
uv tool install aimessenger
|
|
52
|
+
aim init --relay aim.mailows.com --handle your-handle
|
|
53
|
+
aim install-claude
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
- **`aim`** — a CLI for the whole protocol: `ask`, `answer`, `notify`, `inbox`, `contacts`,
|
|
57
|
+
`pair request|approve|deny|revoke`, `alias`, `label`, `thread`, `export`.
|
|
58
|
+
- **`aim channel`** — the Claude Code *channel* MCP server. It wakes the session when a message
|
|
59
|
+
arrives, so a question lands in the conversation instead of waiting to be collected. Claude Code
|
|
60
|
+
starts it for you; you never run it by hand.
|
|
61
|
+
- **`aim-relay`** — the relay server itself, for running your own (`pip install aimessenger[relay]`).
|
|
62
|
+
|
|
63
|
+
Nothing to install is also an option: the same tools are available over a remote MCP server at
|
|
64
|
+
`https://aim.mailows.com/mcp`, where the model asks for new messages rather than being woken by
|
|
65
|
+
them.
|
|
66
|
+
|
|
67
|
+
## How it works
|
|
68
|
+
|
|
69
|
+
Every session has an address shaped `handle@aim.mailows.com/session-name`. A relay carries signed
|
|
70
|
+
messages between addresses and enforces who may write to whom:
|
|
71
|
+
|
|
72
|
+
1. You ask a peer for access. They receive the request with your key fingerprint.
|
|
73
|
+
2. A person approves it on the website. The model has no tool for it and never will, so no incoming
|
|
74
|
+
message can talk it into granting anything.
|
|
75
|
+
3. From then on questions and answers flow. A question waits for one answer until its deadline; if
|
|
76
|
+
the other side is offline, the relay holds the message and delivers it on reconnect.
|
|
77
|
+
|
|
78
|
+
Every envelope is Ed25519-signed and verified by the recipient against a pinned key, so a relay
|
|
79
|
+
cannot forge one. Text that arrives from a peer is data to the model, never instructions — the
|
|
80
|
+
channel repeats that on every connection.
|
|
81
|
+
|
|
82
|
+
## Requirements
|
|
83
|
+
|
|
84
|
+
Python 3.14 or later. The channel needs Claude Code 2.1.268 or later; channels are a research
|
|
85
|
+
preview there, so it currently starts with `--dangerously-load-development-channels server:aim`
|
|
86
|
+
unless your organization allowlists the plugin.
|
|
87
|
+
|
|
88
|
+
## Licence
|
|
89
|
+
|
|
90
|
+
BSD 3-Clause.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# AIM – AI Session Messenger
|
|
2
|
+
|
|
3
|
+
Protokol a nástroje pro **komunikaci mezi AI kódovacími sessionami napříč nástroji i účty** –
|
|
4
|
+
Claude Code, Codex, Gemini CLI, Grok, kdokoli s podporou vzdáleného MCP. Claude si mezi sessionami
|
|
5
|
+
píše sám, ale jen v rámci jednoho seatu a jen s dalšími Claudy – kolega s vlastním seatem v téže
|
|
6
|
+
firmě je už mimo dosah; tady začíná AIM.
|
|
7
|
+
Dotazy a odpovědi v reálném čase, store‑and‑forward pro offline peery, a to jen po **výslovném
|
|
8
|
+
schválení člověkem**, které cizí sessiony smí mluvit s kterými lokálními.
|
|
9
|
+
|
|
10
|
+
- `aim` – klientské CLI a Claude Code *channel* MCP server (`aim channel`)
|
|
11
|
+
- `plugin/` – plugin pro Claude Code (`/plugin install aim@aim`), repozitář je zároveň marketplace
|
|
12
|
+
- `docs/PLUGIN.md` – instalace pluginu, allowlist kanálů a postup vydání
|
|
13
|
+
- `aim-relay` – relay server (Docker, VPS), uzavřený pozvánkami
|
|
14
|
+
- `docs/PLAN.md` – schválený plán a log rozhodnutí
|
|
15
|
+
- `docs/PROTOCOL.md` – specifikace protokolu AIM v1
|
|
16
|
+
- `deploy/` – Docker compose + Caddy pro `aim.mailows.com`
|
|
17
|
+
|
|
18
|
+
Stack: Python 3.14, MCP Python SDK 2.x, PyNaCl (Ed25519), websockets, SQLite.
|
|
19
|
+
|
|
20
|
+
## Rychlý start (vývoj)
|
|
21
|
+
|
|
22
|
+
```powershell
|
|
23
|
+
uv sync
|
|
24
|
+
uv run aim --help
|
|
25
|
+
uv run pytest
|
|
26
|
+
```
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# copy to .env on the VPS (/opt/aim/deploy/.env) and fill in
|
|
2
|
+
AIM_RELAY_HOST=aim.mailows.com
|
|
3
|
+
# a previous domain to keep serving during a move: the API stays reachable there and browsers
|
|
4
|
+
# are redirected to AIM_RELAY_HOST. Empty when there is none, which is the normal case.
|
|
5
|
+
AIM_LEGACY_HOST=
|
|
6
|
+
# externally visible base URL; OAuth metadata and email links are built from it
|
|
7
|
+
AIM_PUBLIC_URL=https://aim.mailows.com
|
|
8
|
+
# master key for server-held identity keys, cookies and links. Generate once and back it up:
|
|
9
|
+
# python -c "import secrets;print(secrets.token_urlsafe(32))"
|
|
10
|
+
# When unset the relay generates one next to the database (secret.key).
|
|
11
|
+
# AIM_SECRET_KEY=
|
|
12
|
+
# outgoing mail; without it verification links only reach the log and nobody can finish signing up
|
|
13
|
+
AIM_SMTP_HOST=mail.namailu.cz
|
|
14
|
+
AIM_SMTP_PORT=587
|
|
15
|
+
AIM_SMTP_STARTTLS=1
|
|
16
|
+
AIM_SMTP_USER=
|
|
17
|
+
AIM_SMTP_PASSWORD=
|
|
18
|
+
AIM_MAIL_FROM=
|
|
19
|
+
# bot protection: Cloudflare Turnstile. The widget only renders when both halves are set.
|
|
20
|
+
AIM_TURNSTILE_SITEKEY=0x4AAAAAAEwrfTVcCkYU7KtT
|
|
21
|
+
AIM_TURNSTILE_SECRET=
|
|
22
|
+
# hostnames the widget may be served from; defaults to the host of AIM_PUBLIC_URL
|
|
23
|
+
# AIM_TURNSTILE_HOSTNAMES=aim.mailows.com
|
|
24
|
+
# AIM_MIN_FORM_SECONDS=2
|
|
25
|
+
# who runs this relay; without these the legal pages say they are incomplete
|
|
26
|
+
AIM_OPERATOR_NAME=DW Technology LLC
|
|
27
|
+
AIM_OPERATOR_ADDRESS=New Mexico, USA
|
|
28
|
+
AIM_OPERATOR_EMAIL=aim@namailu.cz
|
|
29
|
+
# Where `/plugin marketplace add` finds the channel plugin. Leave empty while the marketplace is
|
|
30
|
+
# private: the guide then says the plugin is available on request instead of printing a dead URL.
|
|
31
|
+
AIM_PLUGIN_MARKETPLACE=
|
|
32
|
+
# Administration is done on the host with `docker compose exec relay aim-relay ...`,
|
|
33
|
+
# so shell access to the VPS is what grants it. There is no admin API and no admin token.
|
|
34
|
+
# message retention (seconds), default 30 days
|
|
35
|
+
AIM_MAILBOX_TTL_S=2592000
|
|
36
|
+
# per-sender limits
|
|
37
|
+
AIM_RATE_PER_MIN=60
|
|
38
|
+
AIM_RATE_PER_DAY=2000
|
|
39
|
+
# per-address brakes for callers we have not authenticated yet
|
|
40
|
+
AIM_ENROLL_PER_HOUR=10
|
|
41
|
+
AIM_AUTH_FAILURES_PER_HOUR=30
|
|
42
|
+
# read the caller address from X-Forwarded-For; keep 1 while the relay sits behind Traefik
|
|
43
|
+
AIM_TRUST_PROXY=1
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# AIM relay image - built on the VPS from a git clone (no registry needed)
|
|
2
|
+
FROM python:3.14-slim AS base
|
|
3
|
+
ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1 UV_COMPILE_BYTECODE=1 UV_LINK_MODE=copy
|
|
4
|
+
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
|
|
5
|
+
WORKDIR /app
|
|
6
|
+
COPY pyproject.toml uv.lock README.md ./
|
|
7
|
+
COPY src ./src
|
|
8
|
+
RUN uv sync --frozen --no-dev --extra relay
|
|
9
|
+
RUN useradd --system --uid 10001 --home /data aim && mkdir -p /data && chown aim:aim /data
|
|
10
|
+
USER aim
|
|
11
|
+
VOLUME ["/data"]
|
|
12
|
+
ENV PATH="/app/.venv/bin:$PATH" AIM_DB=/data/relay.sqlite AIM_BIND=0.0.0.0 AIM_PORT=8080
|
|
13
|
+
EXPOSE 8080
|
|
14
|
+
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
|
|
15
|
+
CMD ["python", "-c", "import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://127.0.0.1:8080/health', timeout=4).status == 200 else 1)"]
|
|
16
|
+
CMD ["aim-relay", "serve"]
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Nasazení relay na VPS pepik
|
|
2
|
+
|
|
3
|
+
Stav VPS (inventura 11. 9. 2026): Ubuntu 24.04.4, Docker 29.7 + Compose v5.3, **Traefik v3.7 už drží porty 80/443**
|
|
4
|
+
(compose projekt `/root/traefik`, konfigurace `/root/traefik/traefik.yml`, ACME `/data/traefik/acme.json`),
|
|
5
|
+
externí docker síť `proxy`, entrypointy `web` / `websecure`, certresolver `letsencrypt`. ufw povoluje 22/80/443.
|
|
6
|
+
Relay se proto připojuje **za Traefik** přes labely – žádná vlastní Caddy.
|
|
7
|
+
|
|
8
|
+
## První nasazení
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
# 1. DNS (Cloudflare): A aim.mailows.com -> 62.171.145.148, DNS only (šedý mráček)
|
|
12
|
+
# 2. na VPS
|
|
13
|
+
ssh pepik
|
|
14
|
+
git clone ssh://git@git.facilitygo.com:222/filip/ai-session-messenger.git /opt/aim # read-only deploy key
|
|
15
|
+
cd /opt/aim/deploy
|
|
16
|
+
cp .env.example .env && nano .env # AIM_RELAY_HOST, AIM_ADMIN_TOKEN
|
|
17
|
+
docker compose build --pull && docker compose up -d
|
|
18
|
+
docker compose ps && docker compose logs -f relay # čekat na "listening"
|
|
19
|
+
curl -fsS https://aim.mailows.com/health # Traefik vystaví certifikát při prvním requestu
|
|
20
|
+
# 3. první pozvánka
|
|
21
|
+
docker compose exec relay aim-relay invite create --handle filip --ttl 7d
|
|
22
|
+
# 4. zálohy
|
|
23
|
+
chmod +x /opt/aim/deploy/*.sh
|
|
24
|
+
( crontab -l 2>/dev/null; echo '17 3 * * * /opt/aim/deploy/backup.sh >> /var/log/aim-backup.log 2>&1' ) | crontab -
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Aktualizace
|
|
28
|
+
|
|
29
|
+
`update.sh` dělá `git pull` v `/opt/aim`, takže potřebuje **deploy klíč v Gitea**. Klíč už je na VPS
|
|
30
|
+
vygenerovaný (`/root/.ssh/aim_deploy_ed25519`, `~/.ssh/config` má záznam pro `git.facilitygo.com:222`).
|
|
31
|
+
Jednorázově ho přidejte v Gitea: repo `filip/ai-session-messenger` → Settings → Deploy Keys → Add,
|
|
32
|
+
read-only, hodnota:
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHVPq1M9NmqSEXOWngz4p9C8AK1qfErb8jZ1rjoIn939 aim-deploy@pepik
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Potom na VPS jednou převeďte `/opt/aim` na klon (teď je to jen snapshot nahraný přes `git archive`):
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
ssh pepik
|
|
42
|
+
mv /opt/aim/deploy/.env /root/aim.env
|
|
43
|
+
rm -rf /opt/aim
|
|
44
|
+
git clone ssh://git@git.facilitygo.com:222/filip/ai-session-messenger.git /opt/aim
|
|
45
|
+
mv /root/aim.env /opt/aim/deploy/.env
|
|
46
|
+
chmod +x /opt/aim/deploy/*.sh
|
|
47
|
+
/opt/aim/deploy/update.sh
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Dokud klíč přidaný není, nasazujte snapshotem z vývojového stroje:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
git archive --format=tar HEAD | ssh pepik 'tar -x -C /opt/aim' && ssh pepik '/opt/aim/deploy/update.sh || (cd /opt/aim/deploy && docker compose up -d --build)'
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Ověřený stav (11. 9. 2026)
|
|
57
|
+
|
|
58
|
+
- DNS `aim.mailows.com` → 62.171.145.148 (+ AAAA `2a02:c207:2342:104::1`), režim DNS only.
|
|
59
|
+
- Traefik vydal Let's Encrypt certifikát (`acme.json` obsahuje `aim.mailows.com`), `https://aim.mailows.com/health`
|
|
60
|
+
odpovídá, `http://` přesměrovává na `https://`.
|
|
61
|
+
- Kontejner `aim_relay` běží `healthy`, poslouchá jen na docker síti `proxy`.
|
|
62
|
+
- Pozor na pořadí: certifikát vznikne až **po** vytvoření DNS záznamu. Když se nasadí dřív, Traefik
|
|
63
|
+
zůstane na svém default certifikátu; nový pokus vynutíte `docker compose restart relay`.
|
|
64
|
+
|
|
65
|
+
## Pošta a ochrana proti botům
|
|
66
|
+
|
|
67
|
+
`.env` na VPS drží přihlašovací údaje, do gitu se nikdy nedostane a má práva 600.
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
docker compose exec relay aim-relay mail check # spojení a přihlášení, nic neodešle
|
|
71
|
+
docker compose exec relay aim-relay mail test <adresa> # jedna zkušební zpráva
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Stav 11. 9. 2026: odesílání přes `mail.namailu.cz:587` se STARTTLS funguje, odesílatel `aim@namailu.cz`.
|
|
75
|
+
Pozor, `smtp.namailu.cz` nemá DNS záznam a certifikát ho nepokrývá.
|
|
76
|
+
|
|
77
|
+
Turnstile je zapnutý, obě poloviny konfigurace jsou nastavené. Kontrola:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
docker compose exec relay aim-relay turnstile
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Pošle schválně neplatný token. Odpověď `invalid-input-response` je ta správná: znamená, že relay na
|
|
84
|
+
Cloudflare dosáhne a secret byl přijat. `invalid-input-secret` znamená špatný klíč, síťová chyba
|
|
85
|
+
znamená, že kontejner ven nedosáhne.
|
|
86
|
+
|
|
87
|
+
Když Cloudflare v dashboardu hlásí, že se siteverify nevolá, obvykle to znamená jen to, že widget
|
|
88
|
+
zatím nikdo nevyřešil. Server totiž volá siteverify až ve chvíli, kdy formulář nese token; bez něj
|
|
89
|
+
odmítne dřív, a to je správně.
|
|
90
|
+
|
|
91
|
+
## Poznámky
|
|
92
|
+
- Relay poslouchá jen na docker síti `proxy` (port 8080 není publikován na host).
|
|
93
|
+
- WebSocket přes Traefik funguje bez další konfigurace; klient posílá ping každých 30 s.
|
|
94
|
+
- Data: volume `aim-data` (`/data/relay.sqlite`). Obnova: zastavit relay, nahrát `.sqlite` do volume, spustit.
|
|
95
|
+
- Pokud by se DNS záznam dal do režimu Cloudflare proxy, je nutné v Cloudflare nastavit SSL „Full (strict)“ a počítat
|
|
96
|
+
s idle timeoutem ~100 s na WebSocketu (ping 30 s to pokrývá).
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Consistent SQLite backup of the relay DB (uses sqlite3 .backup inside the container).
|
|
3
|
+
# Cron example (daily 03:17): 17 3 * * * /opt/aim/deploy/backup.sh >> /var/log/aim-backup.log 2>&1
|
|
4
|
+
set -euo pipefail
|
|
5
|
+
cd "$(dirname "$0")"
|
|
6
|
+
BACKUP_DIR=${BACKUP_DIR:-/opt/aim/backups}
|
|
7
|
+
KEEP_DAYS=${KEEP_DAYS:-14}
|
|
8
|
+
mkdir -p "$BACKUP_DIR"
|
|
9
|
+
stamp=$(date +%Y%m%d-%H%M%S)
|
|
10
|
+
docker compose exec -T relay python - <<'PY'
|
|
11
|
+
import sqlite3, os
|
|
12
|
+
src = sqlite3.connect(os.environ.get("AIM_DB", "/data/relay.sqlite"))
|
|
13
|
+
dst = sqlite3.connect("/data/backup.tmp.sqlite")
|
|
14
|
+
src.backup(dst)
|
|
15
|
+
dst.close(); src.close()
|
|
16
|
+
PY
|
|
17
|
+
docker compose cp relay:/data/backup.tmp.sqlite "$BACKUP_DIR/relay-$stamp.sqlite"
|
|
18
|
+
docker compose exec -T relay rm -f /data/backup.tmp.sqlite
|
|
19
|
+
gzip -f "$BACKUP_DIR/relay-$stamp.sqlite"
|
|
20
|
+
find "$BACKUP_DIR" -name 'relay-*.sqlite.gz' -mtime +"$KEEP_DAYS" -delete
|
|
21
|
+
echo "backup ok: $BACKUP_DIR/relay-$stamp.sqlite.gz"
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# AIM relay behind the existing Traefik v3 on VPS pepik.
|
|
2
|
+
# Traefik owns :80/:443, uses the external docker network "proxy",
|
|
3
|
+
# entrypoints "web"/"websecure" and certresolver "letsencrypt".
|
|
4
|
+
services:
|
|
5
|
+
relay:
|
|
6
|
+
build:
|
|
7
|
+
context: ..
|
|
8
|
+
dockerfile: deploy/Dockerfile
|
|
9
|
+
image: aim-relay:local
|
|
10
|
+
container_name: aim_relay
|
|
11
|
+
restart: unless-stopped
|
|
12
|
+
env_file: .env
|
|
13
|
+
environment:
|
|
14
|
+
AIM_DB: /data/relay.sqlite
|
|
15
|
+
AIM_BIND: 0.0.0.0
|
|
16
|
+
AIM_PORT: "8080"
|
|
17
|
+
volumes:
|
|
18
|
+
- aim-data:/data
|
|
19
|
+
networks:
|
|
20
|
+
- proxy
|
|
21
|
+
logging:
|
|
22
|
+
driver: json-file
|
|
23
|
+
options:
|
|
24
|
+
max-size: "10m"
|
|
25
|
+
max-file: "5"
|
|
26
|
+
labels:
|
|
27
|
+
traefik.enable: "true"
|
|
28
|
+
traefik.docker.network: proxy
|
|
29
|
+
# Two Host() matchers, not one with two names: this Traefik takes exactly one parameter
|
|
30
|
+
# per Host(). Traefik asks Let's Encrypt for every name in the rule, and the
|
|
31
|
+
# old domain keeps answering while clients still point at it. Set AIM_LEGACY_HOST to the
|
|
32
|
+
# same value as AIM_RELAY_HOST once nobody does. Unset it falls back to AIM_RELAY_HOST,
|
|
33
|
+
# so a deploy before .env is updated cannot render an empty, invalid Host() rule.
|
|
34
|
+
traefik.http.routers.aim-http.rule: Host(`${AIM_RELAY_HOST}`) || Host(`${AIM_LEGACY_HOST:-${AIM_RELAY_HOST}}`)
|
|
35
|
+
traefik.http.routers.aim-http.entrypoints: web
|
|
36
|
+
traefik.http.routers.aim-http.middlewares: aim-https-redirect
|
|
37
|
+
traefik.http.middlewares.aim-https-redirect.redirectscheme.scheme: https
|
|
38
|
+
traefik.http.middlewares.aim-https-redirect.redirectscheme.permanent: "true"
|
|
39
|
+
traefik.http.routers.aim-https.rule: Host(`${AIM_RELAY_HOST}`) || Host(`${AIM_LEGACY_HOST:-${AIM_RELAY_HOST}}`)
|
|
40
|
+
traefik.http.routers.aim-https.entrypoints: websecure
|
|
41
|
+
traefik.http.routers.aim-https.tls: "true"
|
|
42
|
+
traefik.http.routers.aim-https.tls.certresolver: letsencrypt
|
|
43
|
+
traefik.http.services.aim.loadbalancer.server.port: "8080"
|
|
44
|
+
|
|
45
|
+
volumes:
|
|
46
|
+
aim-data:
|
|
47
|
+
|
|
48
|
+
networks:
|
|
49
|
+
proxy:
|
|
50
|
+
external: true
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Pull latest code and rebuild/restart the relay. Run on the VPS: /opt/aim/deploy/update.sh
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
cd "$(dirname "$0")/.."
|
|
5
|
+
git pull --ff-only
|
|
6
|
+
cd deploy
|
|
7
|
+
docker compose build --pull
|
|
8
|
+
docker compose up -d
|
|
9
|
+
docker compose ps
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Přihlášení do adresáře konektorů Claude
|
|
2
|
+
|
|
3
|
+
Cílem je dostat AIM do adresáře konektorů na claude.ai, aby si ho uživatelé přidali kliknutím místo
|
|
4
|
+
ručního zadávání adresy. Tenhle soubor je kontrolní seznam, ne návod od Anthropicu; ten se může měnit.
|
|
5
|
+
|
|
6
|
+
## Co je splněné
|
|
7
|
+
|
|
8
|
+
| Požadavek | Stav |
|
|
9
|
+
|-----------|------|
|
|
10
|
+
| Vzdálený MCP server přes HTTP | `https://aim.mailows.com/mcp` |
|
|
11
|
+
| OAuth 2.1 jako resource server | autorizační server běží vedle, dynamická registrace klientů, PKCE |
|
|
12
|
+
| Metadata chráněného zdroje (RFC 9728) | `/.well-known/oauth-protected-resource/mcp` |
|
|
13
|
+
| Metadata autorizačního serveru (RFC 8414) | `/.well-known/oauth-authorization-server` |
|
|
14
|
+
| Anotace nástrojů | `readOnlyHint` u čtecích, `openWorldHint` u odesílacích |
|
|
15
|
+
| Název, popis, web a ikona serveru | posílají se v `initialize`, ikona na `/icon.svg` |
|
|
16
|
+
| Veřejné zásady ochrany osobních údajů | `/privacy`, česky i anglicky |
|
|
17
|
+
| Podmínky užití | `/terms`, česky i anglicky |
|
|
18
|
+
| Popis služby pro nové uživatele | `/` a `/docs`, česky i anglicky |
|
|
19
|
+
| Role pro odeslání | primary owner organizace Mailows |
|
|
20
|
+
|
|
21
|
+
## Co ještě chybí
|
|
22
|
+
|
|
23
|
+
1. **Údaje o provozovateli.** Bez nich právní stránky ukazují varování, že nejsou úplné, a neúplné
|
|
24
|
+
zásady ochrany osobních údajů jsou podle zkušeností komunity nejčastější důvod zamítnutí.
|
|
25
|
+
Doplňte do `/opt/aim/deploy/.env` a restartujte:
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
AIM_OPERATOR_NAME=…
|
|
29
|
+
AIM_OPERATOR_ADDRESS=…
|
|
30
|
+
AIM_OPERATOR_EMAIL=…
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
2. **Rozhodnout o otevřené registraci.** Adresář znamená provoz zvenčí. S otevřenou registrací
|
|
34
|
+
přichází moderace, řešení zneužití a mazání účtů na žádost.
|
|
35
|
+
|
|
36
|
+
3. **Vyzkoušet každý nástroj.** Portál si server proskenuje, načte nástroje a nechá potvrdit, že
|
|
37
|
+
fungují. Projděte je ve skutečném klientovi: `aim_status`, `aim_contacts`, `aim_ask`,
|
|
38
|
+
`aim_answer`, `aim_notify`, `aim_receive`, `aim_pending`, `aim_thread`.
|
|
39
|
+
|
|
40
|
+
## Text výpisu
|
|
41
|
+
|
|
42
|
+
Popis v adresáři má vést tím, co ostatní neumí: komunikací **napříč nástroji a napříč seaty**.
|
|
43
|
+
Claude Code si mezi sessionami posílá zprávy sám, ale jen v rámci jednoho seatu a jen mezi Claudy —
|
|
44
|
+
kolega s vlastním seatem v téže firmě je už mimo dosah.
|
|
45
|
+
|
|
46
|
+
> AIM doručí dotaz z jedné kódovací AI session do session někoho jiného — v jiném nástroji
|
|
47
|
+
> (Claude Code, Codex, Gemini CLI, Grok), na jiném seatu, u kolegy ve firmě i u dodavatele — a
|
|
48
|
+
> odpověď přinese zpátky. Kdo s kým smí mluvit, schvaluje člověk v prohlížeči, ne model.
|
|
49
|
+
|
|
50
|
+
Stejná formulace je na `/` a v `description` MCP serveru, ať je výpis konzistentní s tím, co
|
|
51
|
+
recenzent uvidí po připojení.
|
|
52
|
+
|
|
53
|
+
## Postup
|
|
54
|
+
|
|
55
|
+
1. Přihlásit se na claude.ai účtem s rolí owner v organizaci.
|
|
56
|
+
2. Admin settings → adresář → přidat konektor, zvolit vzdálený MCP server.
|
|
57
|
+
3. Zadat `https://aim.mailows.com/mcp`. Portál se připojí, načte nástroje a jejich anotace.
|
|
58
|
+
4. Doplnit údaje pro výpis: název, popis, odkaz na web a na zásady ochrany osobních údajů.
|
|
59
|
+
5. Potvrdit funkčnost nástrojů a odeslat.
|
|
60
|
+
|
|
61
|
+
Recenze nemá zveřejněnou lhůtu, komunita hlásí týdny až měsíce. Na eskalace slouží adresa
|
|
62
|
+
`mcp-review@anthropic.com`.
|
|
63
|
+
|
|
64
|
+
## Druhá cesta: marketplace pluginů
|
|
65
|
+
|
|
66
|
+
Lokální kanál, který umí probouzet session, není konektor, ale plugin Claude Code. **Ten už je
|
|
67
|
+
hotový** (`plugin/`, vlastní marketplace v kořeni repa, podrobnosti v `PLUGIN.md`) a dá se odeslat
|
|
68
|
+
do komunitního marketplace formulářem na
|
|
69
|
+
`claude.ai/admin-settings/directory/submissions/plugins/new`. Před odesláním
|
|
70
|
+
`claude plugin validate plugin/.claude-plugin/plugin.json --strict`.
|
|
71
|
+
|
|
72
|
+
Pozor: komunitní marketplace **není** na allowlistu kanálů, takže i schválený plugin bude u cizích
|
|
73
|
+
uživatelů pořád chtít `--dangerously-load-development-channels`. Ve vlastní organizaci to řeší
|
|
74
|
+
`allowedChannelPlugins` v managed settings. Pro veřejnost vede cesta jen přes oficiální
|
|
75
|
+
`claude-plugins-official`, kam se nepřihlašuje — dokumentace k tomu říká, ať se ozvete
|
|
76
|
+
partnerskému kontaktu u Anthropicu. To je stejný kanál, kterým prošel konektor Mailows.
|
|
77
|
+
|
|
78
|
+
## Ostatní katalogy
|
|
79
|
+
|
|
80
|
+
- **Oficiální MCP registry**: bez schvalování, potřebuje `server.json` a balíček na PyPI.
|
|
81
|
+
Podrobnosti v `ROADMAP.md`.
|
|
82
|
+
- **ChatGPT**: stejný `/mcp` endpoint, navíc ověření domény, definice CSP domén, přihlašovací údaje
|
|
83
|
+
pro recenzenta a pět pozitivních plus tři negativní testovací scénáře.
|
|
84
|
+
- **Grok**: žádný adresář, uživatel si adresu přidá sám.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Přesun na aim.mailows.com
|
|
2
|
+
|
|
3
|
+
Rozhodnuto 15. 9. 2026: kanonická adresa relaye je `aim.mailows.com` místo `aim.aisprava.cz`.
|
|
4
|
+
Důvod je značka — provozovatelem je DW Technology LLC a AIM se má vázat na Mailows, kdežto
|
|
5
|
+
`aisprava.cz` patří k jinému projektu a recenzentovi adresáře to nesedí dohromady.
|
|
6
|
+
|
|
7
|
+
## Proč to není jen přepsání textu
|
|
8
|
+
|
|
9
|
+
Hostitel je **součástí identity**. Adresa uživatele je `handle@host` a adresa session
|
|
10
|
+
`handle@host/session`, takže změnou domény se mění každá adresa v systému. Konkrétně:
|
|
11
|
+
|
|
12
|
+
- **Granty jsou podepsané** svým vydavatelem nad kanonickým JSONem, ve kterém ty adresy jsou.
|
|
13
|
+
Přepsat host v databázi by rozbilo podpis, a u účtů, kde klíč drží uživatel (ne server), ho relay
|
|
14
|
+
znovu podepsat nemůže. Granty se proto musí **vydat znovu**, ne migrovat.
|
|
15
|
+
- **OAuth** vydává metadata odvozená z `AIM_PUBLIC_URL`. Po změně jsou dosavadní registrace klientů
|
|
16
|
+
a tokeny neplatné — každý klient se musí přihlásit znovu.
|
|
17
|
+
- **Turnstile** ověřuje hostname proti seznamu povolených domén, který se nastavuje v Cloudflare
|
|
18
|
+
u toho konkrétního widgetu. Bez doplnění nové domény se formuláře zavřou.
|
|
19
|
+
|
|
20
|
+
K 15. 9. 2026 má relay pět účtů, všechny naše nebo testovací (`filip`, `test-bob`, `zkouska`,
|
|
21
|
+
`magery`, `postatest`). Žádný cizí uživatel na staré adrese neuvázne, takže volíme čistý řez:
|
|
22
|
+
stará doména se ruší a data se nemigrují.
|
|
23
|
+
|
|
24
|
+
## Postup
|
|
25
|
+
|
|
26
|
+
1. **DNS.** V Cloudflare přidat `aim.mailows.com` A → `62.171.145.148`, **DNS only (šedý mráček)**.
|
|
27
|
+
Šedý schválně: přes oranžový by WebSocket podléhal timeoutu ~100 s.
|
|
28
|
+
2. **Turnstile.** Widget musí znát `aim.mailows.com`. Protože `mailows.com` a `aisprava.cz` jsou
|
|
29
|
+
v Cloudflare pod jiným vlastníkem, vznikl **nový widget v účtu mailows** (site key
|
|
30
|
+
`0x4AAAAAAE2-Q3XfzjoHp_U3`); jeho site key i secret patří do `.env`.
|
|
31
|
+
3. **Přepnutí adresy.** V `/opt/aim/deploy/.env`: `AIM_RELAY_HOST=aim.mailows.com`,
|
|
32
|
+
`AIM_PUBLIC_URL=https://aim.mailows.com`, `AIM_TURNSTILE_HOSTNAMES=aim.mailows.com`,
|
|
33
|
+
`AIM_LEGACY_HOST=` (prázdné). Pak `docker compose -f deploy/docker-compose.yml up -d`.
|
|
34
|
+
4. **Certifikát.** Traefik si o něj řekne podle pravidla routeru, ověřit
|
|
35
|
+
`curl https://aim.mailows.com/health`.
|
|
36
|
+
5. **Účty.** Handle zůstávají, mění se jen host v adrese. Nic v databázi se nepřepisuje.
|
|
37
|
+
6. **Klient.** `aim init --relay aim.mailows.com --handle <handle> --force`, pak `aim doctor`.
|
|
38
|
+
7. **Granty vydat znovu**, protože ty staré ukazují na starý host:
|
|
39
|
+
`aim pair grant <peer>@aim.mailows.com/<session> --sessions <moje> --rights ask,notify --ttl 30d`.
|
|
40
|
+
Staré se dají nechat vypršet, nebo `aim pair revoke <grant_id>`.
|
|
41
|
+
8. **Klienti se vzdáleným MCP.** V každém přidat znovu:
|
|
42
|
+
`claude mcp remove aim-web -s user` a `claude mcp add --scope user --transport http aim-web
|
|
43
|
+
https://aim.mailows.com/mcp`, pak `/mcp` a přihlásit.
|
|
44
|
+
9. **Plugin.** `plugin/.mcp.json` doménu neobsahuje, takže se nemění. `plugin.json` a
|
|
45
|
+
`marketplace.json` ano — už přepsané.
|
|
46
|
+
|
|
47
|
+
## Stará doména se ruší
|
|
48
|
+
|
|
49
|
+
Rozhodnuto 15. 9. 2026: `aim.aisprava.cz` se z projektu **ruší úplně**, neběží ani souběžně.
|
|
50
|
+
Souběh by dával smysl, kdyby na staré adrese byli cizí uživatelé; nejsou, všech pět účtů je našich.
|
|
51
|
+
`AIM_LEGACY_HOST` proto zůstává prázdné a v Cloudflare (účet `aisprava.cz`, jiný vlastník) se dá
|
|
52
|
+
`aim` A záznam smazat.
|
|
53
|
+
|
|
54
|
+
Mechanismus souběhu v kódu zůstává pro případ dalšího stěhování: když `AIM_LEGACY_HOST` vyplníte,
|
|
55
|
+
Traefik obslouží obě domény, API a WebSocket na staré dál fungují a prohlížeč dostane 308 na novou.
|
|
56
|
+
Hlídají to testy v `tests/test_legacy_host.py`.
|
|
57
|
+
|
|
58
|
+
## Co ještě nese starý název
|
|
59
|
+
|
|
60
|
+
- **Pošta.** `.env` ukazuje na `aim@mailows.com` přes SMTP `mailows.com`, jenže ten server
|
|
61
|
+
z pepika k 15. 9. 2026 neodpovídá na portech 25, 465, 587 ani 2525. Dokud to tak je, nedorazí
|
|
62
|
+
potvrzení registrace, obnova hesla ani upozornění; funkční nastavení bylo `mail.namailu.cz`
|
|
63
|
+
s odesílatelem `aim@namailu.cz`.
|
|
64
|
+
- `docs/PLAN.md` popisuje stav při návrhu a záměrně se nepřepisuje, aby zůstalo dohledatelné,
|
|
65
|
+
proč se to tehdy rozhodlo jinak.
|