freemygpt 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.
@@ -0,0 +1,20 @@
1
+ version: 2
2
+
3
+ updates:
4
+ - package-ecosystem: "pip"
5
+ directory: "/"
6
+ schedule:
7
+ interval: "weekly"
8
+ day: "monday"
9
+ open-pull-requests-limit: 5
10
+ commit-message:
11
+ prefix: "deps"
12
+
13
+ - package-ecosystem: "github-actions"
14
+ directory: "/"
15
+ schedule:
16
+ interval: "weekly"
17
+ day: "monday"
18
+ open-pull-requests-limit: 5
19
+ commit-message:
20
+ prefix: "ci"
@@ -0,0 +1,43 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ concurrency:
10
+ group: ci-${{ github.ref }}
11
+ cancel-in-progress: true
12
+
13
+ jobs:
14
+ test:
15
+ name: test (${{ matrix.os }} / py${{ matrix.python }})
16
+ runs-on: ${{ matrix.os }}
17
+ strategy:
18
+ fail-fast: false
19
+ matrix:
20
+ os: [ubuntu-latest, macos-latest]
21
+ python: ["3.10", "3.11", "3.12"]
22
+ steps:
23
+ - uses: actions/checkout@v4
24
+
25
+ - name: install uv
26
+ uses: astral-sh/setup-uv@v4
27
+ with:
28
+ version: "0.9.9"
29
+
30
+ - name: set up python
31
+ run: uv python install ${{ matrix.python }}
32
+
33
+ - name: install freemygpt with dev extras
34
+ run: uv pip install --system -e ".[dev]"
35
+
36
+ - name: ruff
37
+ run: uv run --no-sync ruff check src tests
38
+
39
+ - name: mypy
40
+ run: uv run --no-sync mypy src
41
+
42
+ - name: pytest
43
+ run: uv run --no-sync pytest -q
@@ -0,0 +1,33 @@
1
+ name: fork-watch
2
+
3
+ # Logs every new fork and every new star to the Actions summary so the
4
+ # maintainer can monitor supply-chain interest and detect suspicious
5
+ # cloning. GitHub already tracks both in the Insights tab — this file
6
+ # makes the same events visible in the notifications feed and produces
7
+ # a job summary for each event.
8
+
9
+ on:
10
+ fork:
11
+ watch:
12
+ types: [started]
13
+
14
+ jobs:
15
+ log-event:
16
+ runs-on: ubuntu-latest
17
+ steps:
18
+ - name: log fork event
19
+ if: github.event_name == 'fork'
20
+ run: |
21
+ echo "## New fork" >> "$GITHUB_STEP_SUMMARY"
22
+ echo "" >> "$GITHUB_STEP_SUMMARY"
23
+ echo "- forker: [\`${{ github.event.forkee.owner.login }}\`](${{ github.event.forkee.owner.html_url }})" >> "$GITHUB_STEP_SUMMARY"
24
+ echo "- new repo: [${{ github.event.forkee.full_name }}](${{ github.event.forkee.html_url }})" >> "$GITHUB_STEP_SUMMARY"
25
+ echo "- at: \`${{ github.event.forkee.created_at }}\`" >> "$GITHUB_STEP_SUMMARY"
26
+
27
+ - name: log star event
28
+ if: github.event_name == 'watch'
29
+ run: |
30
+ echo "## New star" >> "$GITHUB_STEP_SUMMARY"
31
+ echo "" >> "$GITHUB_STEP_SUMMARY"
32
+ echo "- user: [\`${{ github.event.sender.login }}\`](${{ github.event.sender.html_url }})" >> "$GITHUB_STEP_SUMMARY"
33
+ echo "- stargazers now: \`${{ github.event.repository.stargazers_count }}\`" >> "$GITHUB_STEP_SUMMARY"
@@ -0,0 +1,63 @@
1
+ name: release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+
8
+ jobs:
9
+ build:
10
+ name: build wheel + sdist
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+
15
+ - name: install uv
16
+ uses: astral-sh/setup-uv@v4
17
+ with:
18
+ version: "0.9.9"
19
+
20
+ - name: set up python
21
+ run: uv python install 3.12
22
+
23
+ - name: build
24
+ run: uv build
25
+
26
+ - name: upload dist artifacts
27
+ uses: actions/upload-artifact@v4
28
+ with:
29
+ name: dist
30
+ path: dist/*
31
+
32
+ pypi-publish:
33
+ name: pypi publish
34
+ needs: build
35
+ runs-on: ubuntu-latest
36
+ environment: pypi
37
+ permissions:
38
+ id-token: write # OIDC trusted publisher
39
+ steps:
40
+ - uses: actions/download-artifact@v4
41
+ with:
42
+ name: dist
43
+ path: dist
44
+ - name: publish to PyPI
45
+ uses: pypa/gh-action-pypi-publish@release/v1
46
+
47
+ github-release:
48
+ name: github release
49
+ needs: build
50
+ runs-on: ubuntu-latest
51
+ permissions:
52
+ contents: write
53
+ steps:
54
+ - uses: actions/checkout@v4
55
+ - uses: actions/download-artifact@v4
56
+ with:
57
+ name: dist
58
+ path: dist
59
+ - name: create release
60
+ uses: softprops/action-gh-release@v2
61
+ with:
62
+ files: dist/*
63
+ generate_release_notes: true
@@ -0,0 +1,14 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ .venv/
5
+ .mypy_cache/
6
+ .ruff_cache/
7
+ .pytest_cache/
8
+ dist/
9
+ build/
10
+ *.db
11
+ *.db-journal
12
+ *.sqlite3
13
+ *.sqlite3-journal
14
+ .DS_Store
@@ -0,0 +1,50 @@
1
+ # Changelog
2
+
3
+ All notable changes to FreeMyGPT are documented here. The format is
4
+ based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and
5
+ this project adheres to
6
+ [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.1.0] — 2026-04-08
11
+
12
+ First public alpha. Single flat commit on `main` with the full
13
+ HTTP-to-MCP gateway, two backend adapters, the session store, CLI,
14
+ tests, CI, and release workflow.
15
+
16
+ ### Added
17
+
18
+ - **FastAPI HTTP gateway** with GET-only endpoints so ChatGPT's
19
+ built-in browse tool (which cannot emit POST requests or custom
20
+ headers) can drive local MCP servers without any Custom GPT Action,
21
+ OpenAPI spec, or GitHub plugin.
22
+ - **Two backend adapters** behind a shared `Backend` Protocol:
23
+ - `McpStdioBackend` — wraps the official `mcp` Python SDK
24
+ `stdio_client` + `ClientSession` so any stdio MCP server can be
25
+ exposed through the HTTP surface
26
+ - `CodexBackend` — bundled subprocess wrapper that spawns
27
+ `codex exec <prompt>` and exposes a single synthetic `chat` tool
28
+ so Codex looks like any other MCP backend from the HTTP side
29
+ - **Bearer token auth** — required on every endpoint except
30
+ `/healthz`, accepted via `?token=` query param (for ChatGPT browse)
31
+ or `Authorization: Bearer` header, compared in constant time via
32
+ `hmac.compare_digest`
33
+ - **Refusal to start unauthenticated** — gateway raises at startup if
34
+ `FREEMYGPT_TOKEN` is unset
35
+ - **Thread-safe SQLite session store** with WAL mode and RLock
36
+ serialization so FastAPI worker threads can share one connection
37
+ - **YAML config file** at `~/.freemygpt/config.yaml` mapping backend
38
+ names to launchers, with per-backend env and timeout overrides
39
+ - **CLI**: `freemygpt serve | doctor | new-token`
40
+ - **Tests**: 16 passing (config loader + full HTTP app with a fake
41
+ backend swapped in for the factory)
42
+ - **CI**: ruff, mypy `--strict`, pytest on macOS + Ubuntu across
43
+ Python 3.10 / 3.11 / 3.12
44
+ - **Release workflow**: tag-triggered wheel build, PyPI publish via
45
+ OIDC trusted publisher, and GitHub release creation
46
+ - **Security posture**: `SECURITY.md` with private disclosure via
47
+ GitHub advisories, `CODEOWNERS`, Dependabot weekly updates,
48
+ `fork-watch` workflow that logs every fork and star to the Actions
49
+ summary, branch protection on `main` blocking force pushes and
50
+ deletions with linear history required
@@ -0,0 +1,7 @@
1
+ # Every path in this repository is owned by the repository maintainer.
2
+ # GitHub auto-requests review from CODEOWNERS on every pull request.
3
+ #
4
+ # Maintainer: Michael Adam Groberman
5
+ # GitHub: https://github.com/MichaelAdamGroberman
6
+ # LinkedIn: https://www.linkedin.com/in/michael-adam-groberman/
7
+ * @MichaelAdamGroberman
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 FreeMyGPT contributors
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,166 @@
1
+ Metadata-Version: 2.4
2
+ Name: freemygpt
3
+ Version: 0.1.0
4
+ Summary: FreeMyGPT — HTTP gateway that lets ChatGPT (and any LLM) drive any local MCP server via simple GET requests. Hybrid: MCP stdio backends by default, Codex CLI and other runtimes via bundled adapters.
5
+ Project-URL: Homepage, https://github.com/MichaelAdamGroberman/FreeMyGPT
6
+ Project-URL: Issues, https://github.com/MichaelAdamGroberman/FreeMyGPT/issues
7
+ Author: FreeMyGPT contributors
8
+ License: MIT
9
+ License-File: LICENSE
10
+ Keywords: bridge,chatgpt,claude,codex,freemygpt,gateway,mcp,openai
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Framework :: FastAPI
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3 :: Only
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
+ Requires-Python: <3.13,>=3.10
21
+ Requires-Dist: fastapi<0.120,>=0.115
22
+ Requires-Dist: httpx<1.0,>=0.28
23
+ Requires-Dist: mcp<2.0,>=1.26.0
24
+ Requires-Dist: pyyaml<7.0,>=6.0
25
+ Requires-Dist: uvicorn[standard]<0.40,>=0.32
26
+ Provides-Extra: dev
27
+ Requires-Dist: mypy>=1.13; extra == 'dev'
28
+ Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
29
+ Requires-Dist: pytest>=8.3; extra == 'dev'
30
+ Requires-Dist: ruff>=0.8; extra == 'dev'
31
+ Requires-Dist: types-pyyaml>=6.0; extra == 'dev'
32
+ Description-Content-Type: text/markdown
33
+
34
+ # FreeMyGPT
35
+
36
+ > **Free ChatGPT from its sandbox.** FreeMyGPT is a tiny HTTP gateway that lets ChatGPT (and any other LLM with an HTTP fetcher) drive **any local MCP server** — Gr0m_Mem, Codex CLI, Kali MCP, Home Assistant MCP, or anything else that speaks the Model Context Protocol — using nothing but **simple GET requests**. No Custom GPT Actions, no GitHub plugin, no OAuth dance, no POST bodies.
37
+
38
+ ```
39
+ ChatGPT ──GET──► FreeMyGPT ──stdio──► MCP server (any)
40
+ └─────► Codex CLI (subprocess)
41
+ ```
42
+
43
+ ## Why
44
+
45
+ - ChatGPT's built-in browse tool can **read URLs** but cannot send POST requests or custom headers. Everyone else's "let ChatGPT call your API" guide assumes Custom GPT Actions. FreeMyGPT assumes you do not have that option.
46
+ - Local MCP servers are powerful (Gr0m_Mem, the Kali server, Home Assistant, Codex) but they only speak stdio. They cannot be reached from a ChatGPT conversation by default.
47
+ - FreeMyGPT is the thinnest possible layer between them: a FastAPI app that spawns each MCP server on first use, forwards `call_tool` requests, and returns the result as JSON in the HTTP response. Bearer token auth via `?token=…` query param so ChatGPT can pass it without setting headers.
48
+
49
+ ## Architecture
50
+
51
+ - **HTTP frontend** (FastAPI, stdio) — GET-only, JSON responses
52
+ - **Hybrid backends**:
53
+ - `mcp` — any stdio MCP server (official `mcp` Python SDK client)
54
+ - `codex` — bundled wrapper that spawns `codex exec <prompt>` and exposes a single `chat` tool, so Codex looks like any other MCP backend from the HTTP side
55
+ - **Bearer token auth** — required on every endpoint except `/healthz`, read from an env var, matched in constant time
56
+ - **Session store** — SQLite; stores chat transcripts so ChatGPT can poll long-running sessions without losing history
57
+ - **One config file** — YAML with an `auth` block and a `backends` map; see `config.example.yaml`
58
+
59
+ ## HTTP surface
60
+
61
+ ```
62
+ GET /healthz (no auth)
63
+ GET /backends ?token=...
64
+ GET /{backend}/tools ?token=...
65
+ GET /{backend}/call/{tool} ?token=...&arg1=...&arg2=...
66
+ GET /{backend}/sessions/new ?token=...&label=...
67
+ GET /{backend}/sessions/{sid}/send ?token=...&message=...
68
+ GET /{backend}/sessions/{sid}/poll ?token=...&since=<id>
69
+ GET /{backend}/sessions/{sid}/close ?token=...
70
+ ```
71
+
72
+ **Tool arguments** are passed as query parameters. Simple scalars (strings, ints, floats, bools) are coerced automatically. For structured arguments, pass them as a JSON blob in `args_json`:
73
+
74
+ ```
75
+ GET /gr0m_mem/call/mem_record_decision?token=...&args_json={"subject":"db","decision":"Postgres","rationale":"concurrent writes"}
76
+ ```
77
+
78
+ ## Quick start
79
+
80
+ ```bash
81
+ pip install freemygpt
82
+
83
+ # 1. Make a token
84
+ export FREEMYGPT_TOKEN="$(freemygpt new-token)"
85
+
86
+ # 2. Write a config
87
+ mkdir -p ~/.freemygpt
88
+ cp $(python -c "import freemygpt, os; print(os.path.join(os.path.dirname(freemygpt.__file__), '..', '..', 'config.example.yaml'))") ~/.freemygpt/config.yaml
89
+ # edit to enable the backends you want
90
+
91
+ # 3. Sanity check
92
+ freemygpt doctor
93
+
94
+ # 4. Run
95
+ freemygpt serve --host 127.0.0.1 --port 8933
96
+ ```
97
+
98
+ ## Exposing it to ChatGPT
99
+
100
+ ChatGPT needs to reach the gateway over the public internet. Pick any reverse tunnel:
101
+
102
+ ### Option A — Cloudflare Tunnel (recommended, free, no account required for quick tunnels)
103
+
104
+ ```bash
105
+ brew install cloudflared
106
+ cloudflared tunnel --url http://127.0.0.1:8933
107
+ ```
108
+
109
+ Cloudflared prints a `https://<random>.trycloudflare.com` URL. Paste it into your ChatGPT conversation with the token appended:
110
+
111
+ ```
112
+ https://<random>.trycloudflare.com/gr0m_mem/call/mem_wakeup?token=<your token>
113
+ ```
114
+
115
+ ChatGPT will browse the URL and inline the JSON response.
116
+
117
+ ### Option B — Tailscale Funnel
118
+
119
+ If your machine is already on Tailscale, enable Funnel on port 8933 and use the `*.ts.net` hostname. Token auth still applies.
120
+
121
+ ### Option C — ngrok
122
+
123
+ ```bash
124
+ ngrok http 8933
125
+ ```
126
+
127
+ Same idea.
128
+
129
+ ## Using it from a ChatGPT conversation
130
+
131
+ Once the URL is live and the token is in the query string, a ChatGPT conversation looks like:
132
+
133
+ > **You:** Fetch `https://tunnel.example.com/gr0m_mem/call/mem_wakeup?token=XYZ` and summarize the response.
134
+ >
135
+ > **ChatGPT:** *(browses the URL, receives the JSON snapshot)* You're Michael, a software engineer on macOS; active project is the FreeMyGPT launch; recent decisions locked in: Postgres for the database (concurrent writes), Clerk over Auth0 (better DX), SQLite FTS5 is the zero-dep default for Gr0m_Mem.
136
+
137
+ Because the responses are plain JSON, any LLM with an HTTP fetcher (Claude browsing, Gemini's `google_search_retrieval`, local Llama with a URL-fetching tool, etc.) can use the exact same URLs.
138
+
139
+ ## Security posture
140
+
141
+ - Bearer token required on every authenticated endpoint, compared in constant time
142
+ - Gateway refuses to start if the configured env var is empty
143
+ - Every backend runs as a subprocess of the gateway — no network listener exposed
144
+ - Session state in SQLite with `PRAGMA foreign_keys=ON`; sessions delete their messages on close
145
+ - `SECURITY.md` documents private vulnerability reporting via GitHub advisories
146
+ - Branch protection on every long-lived branch (no force pushes, no deletions, linear history)
147
+ - CI runs ruff, mypy `--strict`, and the full test suite on every push
148
+
149
+ See [`SECURITY.md`](SECURITY.md) for the full disclosure policy and out-of-scope list.
150
+
151
+ ## Status
152
+
153
+ v0.1.0 alpha. API surface is stable; the wire format (`{"text": ..., "structured": ..., "is_error": ...}`) is not expected to change. Breaking changes will bump the minor version until v1.0.
154
+
155
+ ## License
156
+
157
+ MIT — see [LICENSE](LICENSE).
158
+
159
+ ## Contact
160
+
161
+ Maintained by **Michael Adam Groberman**.
162
+
163
+ - **GitHub**: [@MichaelAdamGroberman](https://github.com/MichaelAdamGroberman)
164
+ - **LinkedIn**: [michael-adam-groberman](https://www.linkedin.com/in/michael-adam-groberman/)
165
+
166
+ For security reports, use GitHub private vulnerability advisories (see [SECURITY.md](SECURITY.md)) — **do not** use LinkedIn DMs for sensitive disclosures.
@@ -0,0 +1,133 @@
1
+ # FreeMyGPT
2
+
3
+ > **Free ChatGPT from its sandbox.** FreeMyGPT is a tiny HTTP gateway that lets ChatGPT (and any other LLM with an HTTP fetcher) drive **any local MCP server** — Gr0m_Mem, Codex CLI, Kali MCP, Home Assistant MCP, or anything else that speaks the Model Context Protocol — using nothing but **simple GET requests**. No Custom GPT Actions, no GitHub plugin, no OAuth dance, no POST bodies.
4
+
5
+ ```
6
+ ChatGPT ──GET──► FreeMyGPT ──stdio──► MCP server (any)
7
+ └─────► Codex CLI (subprocess)
8
+ ```
9
+
10
+ ## Why
11
+
12
+ - ChatGPT's built-in browse tool can **read URLs** but cannot send POST requests or custom headers. Everyone else's "let ChatGPT call your API" guide assumes Custom GPT Actions. FreeMyGPT assumes you do not have that option.
13
+ - Local MCP servers are powerful (Gr0m_Mem, the Kali server, Home Assistant, Codex) but they only speak stdio. They cannot be reached from a ChatGPT conversation by default.
14
+ - FreeMyGPT is the thinnest possible layer between them: a FastAPI app that spawns each MCP server on first use, forwards `call_tool` requests, and returns the result as JSON in the HTTP response. Bearer token auth via `?token=…` query param so ChatGPT can pass it without setting headers.
15
+
16
+ ## Architecture
17
+
18
+ - **HTTP frontend** (FastAPI, stdio) — GET-only, JSON responses
19
+ - **Hybrid backends**:
20
+ - `mcp` — any stdio MCP server (official `mcp` Python SDK client)
21
+ - `codex` — bundled wrapper that spawns `codex exec <prompt>` and exposes a single `chat` tool, so Codex looks like any other MCP backend from the HTTP side
22
+ - **Bearer token auth** — required on every endpoint except `/healthz`, read from an env var, matched in constant time
23
+ - **Session store** — SQLite; stores chat transcripts so ChatGPT can poll long-running sessions without losing history
24
+ - **One config file** — YAML with an `auth` block and a `backends` map; see `config.example.yaml`
25
+
26
+ ## HTTP surface
27
+
28
+ ```
29
+ GET /healthz (no auth)
30
+ GET /backends ?token=...
31
+ GET /{backend}/tools ?token=...
32
+ GET /{backend}/call/{tool} ?token=...&arg1=...&arg2=...
33
+ GET /{backend}/sessions/new ?token=...&label=...
34
+ GET /{backend}/sessions/{sid}/send ?token=...&message=...
35
+ GET /{backend}/sessions/{sid}/poll ?token=...&since=<id>
36
+ GET /{backend}/sessions/{sid}/close ?token=...
37
+ ```
38
+
39
+ **Tool arguments** are passed as query parameters. Simple scalars (strings, ints, floats, bools) are coerced automatically. For structured arguments, pass them as a JSON blob in `args_json`:
40
+
41
+ ```
42
+ GET /gr0m_mem/call/mem_record_decision?token=...&args_json={"subject":"db","decision":"Postgres","rationale":"concurrent writes"}
43
+ ```
44
+
45
+ ## Quick start
46
+
47
+ ```bash
48
+ pip install freemygpt
49
+
50
+ # 1. Make a token
51
+ export FREEMYGPT_TOKEN="$(freemygpt new-token)"
52
+
53
+ # 2. Write a config
54
+ mkdir -p ~/.freemygpt
55
+ cp $(python -c "import freemygpt, os; print(os.path.join(os.path.dirname(freemygpt.__file__), '..', '..', 'config.example.yaml'))") ~/.freemygpt/config.yaml
56
+ # edit to enable the backends you want
57
+
58
+ # 3. Sanity check
59
+ freemygpt doctor
60
+
61
+ # 4. Run
62
+ freemygpt serve --host 127.0.0.1 --port 8933
63
+ ```
64
+
65
+ ## Exposing it to ChatGPT
66
+
67
+ ChatGPT needs to reach the gateway over the public internet. Pick any reverse tunnel:
68
+
69
+ ### Option A — Cloudflare Tunnel (recommended, free, no account required for quick tunnels)
70
+
71
+ ```bash
72
+ brew install cloudflared
73
+ cloudflared tunnel --url http://127.0.0.1:8933
74
+ ```
75
+
76
+ Cloudflared prints a `https://<random>.trycloudflare.com` URL. Paste it into your ChatGPT conversation with the token appended:
77
+
78
+ ```
79
+ https://<random>.trycloudflare.com/gr0m_mem/call/mem_wakeup?token=<your token>
80
+ ```
81
+
82
+ ChatGPT will browse the URL and inline the JSON response.
83
+
84
+ ### Option B — Tailscale Funnel
85
+
86
+ If your machine is already on Tailscale, enable Funnel on port 8933 and use the `*.ts.net` hostname. Token auth still applies.
87
+
88
+ ### Option C — ngrok
89
+
90
+ ```bash
91
+ ngrok http 8933
92
+ ```
93
+
94
+ Same idea.
95
+
96
+ ## Using it from a ChatGPT conversation
97
+
98
+ Once the URL is live and the token is in the query string, a ChatGPT conversation looks like:
99
+
100
+ > **You:** Fetch `https://tunnel.example.com/gr0m_mem/call/mem_wakeup?token=XYZ` and summarize the response.
101
+ >
102
+ > **ChatGPT:** *(browses the URL, receives the JSON snapshot)* You're Michael, a software engineer on macOS; active project is the FreeMyGPT launch; recent decisions locked in: Postgres for the database (concurrent writes), Clerk over Auth0 (better DX), SQLite FTS5 is the zero-dep default for Gr0m_Mem.
103
+
104
+ Because the responses are plain JSON, any LLM with an HTTP fetcher (Claude browsing, Gemini's `google_search_retrieval`, local Llama with a URL-fetching tool, etc.) can use the exact same URLs.
105
+
106
+ ## Security posture
107
+
108
+ - Bearer token required on every authenticated endpoint, compared in constant time
109
+ - Gateway refuses to start if the configured env var is empty
110
+ - Every backend runs as a subprocess of the gateway — no network listener exposed
111
+ - Session state in SQLite with `PRAGMA foreign_keys=ON`; sessions delete their messages on close
112
+ - `SECURITY.md` documents private vulnerability reporting via GitHub advisories
113
+ - Branch protection on every long-lived branch (no force pushes, no deletions, linear history)
114
+ - CI runs ruff, mypy `--strict`, and the full test suite on every push
115
+
116
+ See [`SECURITY.md`](SECURITY.md) for the full disclosure policy and out-of-scope list.
117
+
118
+ ## Status
119
+
120
+ v0.1.0 alpha. API surface is stable; the wire format (`{"text": ..., "structured": ..., "is_error": ...}`) is not expected to change. Breaking changes will bump the minor version until v1.0.
121
+
122
+ ## License
123
+
124
+ MIT — see [LICENSE](LICENSE).
125
+
126
+ ## Contact
127
+
128
+ Maintained by **Michael Adam Groberman**.
129
+
130
+ - **GitHub**: [@MichaelAdamGroberman](https://github.com/MichaelAdamGroberman)
131
+ - **LinkedIn**: [michael-adam-groberman](https://www.linkedin.com/in/michael-adam-groberman/)
132
+
133
+ For security reports, use GitHub private vulnerability advisories (see [SECURITY.md](SECURITY.md)) — **do not** use LinkedIn DMs for sensitive disclosures.
@@ -0,0 +1,70 @@
1
+ # Security Policy
2
+
3
+ ## Supported versions
4
+
5
+ FreeMyGPT is in `0.1.x` alpha. Only the latest tagged release on `main`
6
+ receives security fixes.
7
+
8
+ | Branch | Status | Fixes |
9
+ |---------|---------|-------|
10
+ | `main` | current | ✅ |
11
+ | earlier | n/a | ❌ |
12
+
13
+ ## Reporting a vulnerability
14
+
15
+ **Please do not open a public issue for security reports.** Instead:
16
+
17
+ 1. Open a GitHub **private vulnerability report** via the "Report a
18
+ vulnerability" button on the Security tab:
19
+ <https://github.com/MichaelAdamGroberman/FreeMyGPT/security/advisories/new>
20
+ 2. Or email the maintainer directly (see GitHub profile).
21
+
22
+ Include:
23
+
24
+ - The affected version and commit SHA
25
+ - A minimal reproduction (the exact request sequence that demonstrates
26
+ the issue)
27
+ - Impact — what data, state, or capability an attacker could gain
28
+
29
+ You will receive an initial response within 72 hours. Fixes for
30
+ confirmed vulnerabilities are prioritized; credit is given by default
31
+ unless you request anonymity.
32
+
33
+ ## Scope
34
+
35
+ In scope:
36
+
37
+ - Authentication bypasses (missing / weak / timing-sensitive token
38
+ checks on any authenticated endpoint)
39
+ - Command injection through query parameters into subprocess backends
40
+ (the Codex backend and any `mcp` backend that forwards arguments to
41
+ a child process)
42
+ - Session-state leakage between tenants
43
+ - Denial of service from an unauthenticated caller (authenticated DoS
44
+ is out of scope — bring your own rate limiter)
45
+ - Supply chain issues in the build and release workflows
46
+
47
+ Out of scope:
48
+
49
+ - Attacks that require an attacker already on the same machine with
50
+ read access to `~/.freemygpt/sessions.db`
51
+ - Vulnerabilities in the backends themselves (the MCP server or the
52
+ Codex CLI) — report those upstream
53
+ - Misconfigurations (missing token, exposed port) — the gateway
54
+ refuses to start without a token but cannot defend against a user
55
+ deliberately binding it to `0.0.0.0` behind no firewall
56
+
57
+ ## Hardening applied by default
58
+
59
+ - Bearer token required on every endpoint except `/healthz`; compared
60
+ in constant time via `hmac.compare_digest`
61
+ - The gateway raises at startup if the token env var is unset
62
+ - Every subprocess backend inherits a scrubbed environment (only the
63
+ keys explicitly listed in the config's `env` block plus the
64
+ process's own environment) — no secret leakage via child env
65
+ - Session-owned SQLite databases enable `foreign_keys=ON` and
66
+ `journal_mode=WAL` and cascade-delete messages when a session closes
67
+ - Branch protection on `main` blocks force pushes, deletions, and
68
+ non-linear history; code owner reviews required on every PR
69
+ - Secret scanning + push protection + Dependabot security updates
70
+ enabled on the repository
@@ -0,0 +1,39 @@
1
+ # FreeMyGPT — example config
2
+ #
3
+ # Copy this file to ~/.freemygpt/config.yaml and edit it, or set
4
+ # FREEMYGPT_CONFIG to point at a different location. The bridge refuses
5
+ # to start if no config is found or no backends are defined.
6
+
7
+ auth:
8
+ # Bearer token required on every authenticated request. Generate a
9
+ # fresh one with:
10
+ # freemygpt new-token
11
+ # and export it in the environment before running `freemygpt serve`:
12
+ # export FREEMYGPT_TOKEN="<value>"
13
+ token_env: FREEMYGPT_TOKEN
14
+
15
+ backends:
16
+ # Example 1: the Gr0m_Mem persistent memory brain over stdio MCP.
17
+ # Install Gr0m_Mem first: pip install gr0m-mem
18
+ gr0m_mem:
19
+ type: mcp
20
+ command: python
21
+ args: ["-m", "gr0m_mem.mcp_server"]
22
+
23
+ # Example 2: OpenAI Codex CLI as a single `chat` tool. The bridge
24
+ # spawns `codex exec <message>` per call. Adjust the args if your
25
+ # local Codex binary uses a different calling convention.
26
+ codex:
27
+ type: codex
28
+ command: codex
29
+ args: ["exec"]
30
+ default_timeout_s: 300
31
+
32
+ # Example 3: any other stdio MCP server — Kali tools, Home Assistant,
33
+ # your own project — just point `command` + `args` at the launcher.
34
+ # kali:
35
+ # type: mcp
36
+ # command: /usr/local/bin/kali-mcp
37
+ # args: []
38
+ # env:
39
+ # KALI_HOST: 10.0.0.29