## Problem
Messaging startup computed a relative path from `ALLOWED_DIR` to FCC's
plan directory. Windows raises before Telegram or Discord polling starts
when those paths are on different drives, while Claude requires custom
plan directories to remain inside the project root. Fixes#1077.
## Changes
| Before | After |
| --- | --- |
| Runtime startup converted FCC's plan path relative to the customer
workspace. | Runtime startup no longer computes or transports a custom
plan path. |
| Managed Claude configuration carried `plans_directory` through four
ownership layers. | Managed Claude relies on its native user-level plan
storage. |
| `~/.fcc/agent_workspace` was described as a Claude workspace. | The
existing path is explicitly owned as messaging state for
`sessions.json`. |
| Cross-volume `ALLOWED_DIR` values could disable messaging startup. |
`ALLOWED_DIR` remains the project workspace regardless of filesystem
volume. |
## Problem
Claude proxy environment policy was duplicated between `fcc-claude`,
managed messaging, and live smoke drivers. Managed messaging preserved a
legacy endpoint variable, inherited more Anthropic state, and did not
disable nonessential traffic, so FCC-launched Claude sessions could
drift apart.
## Changes
| Before | After |
| --- | --- |
| `fcc-claude` and managed messaging assembled proxy environments
independently. | One shared owner strips inherited Anthropic variables
and configures proxy URL, auth, discovery, compaction, and
nonessential-traffic policy. |
| Managed messaging carried a `/v1` API URL and converted it back to a
proxy root while also setting a legacy endpoint variable. | Managed
messaging receives the loopback-safe proxy root and uses the supported
`ANTHROPIC_BASE_URL` contract directly. |
| Managed and interactive policy could diverge while smoke drivers
duplicated both shapes. | `fcc-claude`, messaging, and Claude smoke
drivers use the same canonical environment builder. |
| Managed execution concerns were mixed with shared proxy policy. |
Messaging adds only noninteractive process settings and keeps `--model
opus` plus stream-JSON flags in command construction. |
| IDE examples left nonessential Anthropic traffic enabled. | VS Code
and JetBrains examples disable nonessential Anthropic traffic. |
<!-- greptile_comment -->
<details open><summary><h3>Greptile Summary</h3></summary>
This PR centralizes Claude Code proxy environment setup for FCC-launched
sessions. The main changes are:
- Adds one shared builder for Claude proxy environment variables.
- Routes managed messaging sessions through the same proxy policy as
`fcc-claude`.
- Strips inherited `ANTHROPIC_*` state before launching Claude.
- Sets the nonessential-traffic disable flag for managed and interactive
Claude launches.
- Updates smoke tests, docs, and version metadata for the new proxy-root
URL shape.
</details>
<h3>Confidence Score: 5/5</h3>
This looks safe to merge.
No blocking issues were found in the changed code. Managed Claude
launches now use the shared environment builder, and the managed path
now sets the nonessential-traffic disable flag.
No files need attention.
<details><summary><h3><a href="https://www.greptile.com/trex"><img
alt="T-Rex"
src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg"
height="20" align="absmiddle"></a> T-Rex Logs</h3></summary>
**What T-Rex did**
- The executable harness claude\_env\_policy\_harness.py was generated
to enable direct module-level runtime proof without requiring a real
Claude binary or live Anthropic credentials.
- A focused pytest run was executed, and it completed with 14 tests
passing and exit code 0, validating the harness workflow.
<a
href="https://app.greptile.com/trex/runs/14173386/artifacts"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifactsDark.svg?v=4"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=4"><img
alt="View all artifacts"
src="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=4"></picture></a>
<sub><a href="https://www.greptile.com/trex"><img alt="T-Rex"
src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg"
height="14" align="absmiddle"></a> Ran code and verified through
T-Rex</sub>
</details>
<details open><summary><h3>Important Files Changed</h3></summary>
| Filename | Overview |
|----------|----------|
| src/free_claude_code/cli/claude_env.py | Adds the shared Claude proxy
environment builder and canonical traffic-disable policy. |
| src/free_claude_code/cli/managed/claude.py | Delegates managed Claude
environment construction to the shared proxy builder. |
| src/free_claude_code/runtime/application.py | Passes the loopback-safe
proxy root into the managed Claude session manager. |
| src/free_claude_code/cli/managed/session.py | Renames managed session
URL state to use the proxy-root contract. |
| src/free_claude_code/cli/managed/manager.py | Carries the proxy-root
URL through manager-created managed sessions. |
</details>
<sub>Reviews (2): Last reviewed commit: ["Keep README focused on client
setup"](https://github.com/alishahryar1/free-claude-code/commit/83739a2f8953771ec9e447fc83a2057b08708891)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=43684511)</sub>
<!-- /greptile_comment -->
## Problem
Runtime modules were published as generic top-level packages like `api`,
`cli`, and `providers`. That shape is fragile for PyPI packaging and
weakens explicit ownership boundaries.
## Changes
| Before | After |
| --- | --- |
| Runtime code lived in root-level packages. | Runtime code lives under
`src/free_claude_code/`. |
| Console scripts targeted top-level modules. | Console scripts target
namespaced modules. |
| Tests and smoke helpers imported old package roots. | Tests and smoke
helpers import `free_claude_code.*`. |
| Packaging listed six root packages. | Packaging builds the single
namespaced package. |
| Contracts allowed old root package directories. | Contracts require
the src namespace and reject old root imports. |
<!-- greptile_comment -->
<details open><summary><h3>Greptile Summary</h3></summary>
This PR moves the runtime packages into the `src/free_claude_code`
namespace. The main changes are:
- Console scripts now point to `free_claude_code.*` entrypoints.
- Runtime imports, tests, and smoke helpers now use the namespaced
package.
- Packaging now builds the single `src/free_claude_code` package.
- Contract tests now reject old top-level runtime package roots and
imports.
</details>
<h3>Confidence Score: 5/5</h3>
This PR is safe to merge with minimal risk.
The changes are a broad but mostly mechanical namespace and
package-layout migration with updated packaging, tests, and contract
coverage.
No files require special attention.
<details><summary><h3><a href="https://www.greptile.com/trex"><img
alt="T-Rex"
src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg"
height="20" align="absmiddle"></a> T-Rex Logs</h3></summary>
**What T-Rex did**
- Reviewed the primary contract validation by examining the namespace
validation log, which documents the exact commands executed, the working
directory, exit codes, pytest output, wheel build output, install
output, and import/entrypoint resolution.
- Verified the wheel listing by inspecting the wheel listing artifact,
confirming the available wheel filenames for the namespace validation.
- Ran and inspected the isolated import/entrypoint validation harness
saved as package-installed-import-check.py to validate import resolution
and entrypoint exposure.
- Captured and noted the wheel filename record in
package-wheel-filename.txt to enable traceability of the observed
artifact.
<a
href="https://app.greptile.com/trex/runs/13810533/artifacts"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifactsDark.svg?v=4"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=4"><img
alt="View all artifacts"
src="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=4"></picture></a>
<sub><a href="https://www.greptile.com/trex"><img alt="T-Rex"
src="https://greptile-static-assets.s3.amazonaws.com/trex/trex_green.svg"
height="14" align="absmiddle"></a> Ran code and verified through
T-Rex</sub>
</details>
<details open><summary><h3>Important Files Changed</h3></summary>
| Filename | Overview |
|----------|----------|
| pyproject.toml | Updates packaging to build the single
`src/free_claude_code` package and retargets console scripts to
namespaced modules. |
| src/free_claude_code/config/env_template.py | Loads `.env.example`
from packaged resources with a source-checkout fallback after the
runtime package move. |
| src/free_claude_code/cli/entrypoints.py | Updates CLI entrypoint
imports to `free_claude_code.*` and continues to use the shared env
template loader. |
| src/free_claude_code/api/routes.py | Retargets API route dependencies
and handlers to the namespaced package without changing route behavior.
|
| src/free_claude_code/api/app.py | Updates app factory imports to the
namespaced package while preserving middleware, routers, and exception
handling. |
| src/free_claude_code/providers/runtime/factory.py | Updates lazy
provider factory imports to `free_claude_code.providers.*` under the new
package layout. |
| tests/contracts/test_import_boundaries.py | Adds contract coverage
requiring runtime packages to live under `src/free_claude_code` and
rejecting old top-level imports. |
| smoke/lib/child_process.py | Updates smoke child-process helpers to
import CLI entrypoints from the namespaced package. |
| README.md | Updates the project layout and extension guidance to refer
to `src/free_claude_code` and importable `free_claude_code.*` modules. |
| uv.lock | Reflects the package version bump associated with the
runtime packaging move. |
</details>
<details open><summary><h3>Sequence Diagram</h3></summary>
<a href="#gh-light-mode-only">
```mermaid
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant User as User / CLI
participant Script as Console script
participant Pkg as free_claude_code package
participant API as free_claude_code.api
participant Runtime as free_claude_code.providers.runtime
participant Provider as Provider adapter
User->>Script: run fcc-server / free-claude-code
Script->>Pkg: load free_claude_code.cli.entrypoints:serve
Pkg->>API: create FastAPI app and routes
API->>Runtime: resolve configured provider
Runtime->>Provider: instantiate namespaced adapter
Provider-->>Runtime: stream/model responses
Runtime-->>API: provider result
API-->>User: Anthropic/OpenAI-compatible response
```
</a>
<a href="#gh-dark-mode-only">
```mermaid
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant User as User / CLI
participant Script as Console script
participant Pkg as free_claude_code package
participant API as free_claude_code.api
participant Runtime as free_claude_code.providers.runtime
participant Provider as Provider adapter
User->>Script: run fcc-server / free-claude-code
Script->>Pkg: load free_claude_code.cli.entrypoints:serve
Pkg->>API: create FastAPI app and routes
API->>Runtime: resolve configured provider
Runtime->>Provider: instantiate namespaced adapter
Provider-->>Runtime: stream/model responses
Runtime-->>API: provider result
API-->>User: Anthropic/OpenAI-compatible response
```
</a>
</details>
<sub>Reviews (2): Last reviewed commit: ["Fix documented package import
paths"](https://github.com/alishahryar1/free-claude-code/commit/bfa9f2704c45f3684da39657d5e13f3814e5d450)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=42950471)</sub>
<!-- /greptile_comment -->
## Problem
The CLI package preserved a generic adapter layer and managed Codex
parser path that did not match the supported customer workflows.
Messaging runs Claude Code sessions, while Codex is supported through
`fcc-codex` and extensions.
## Changes
| Before | After |
| --- | --- |
| `fcc-claude` and `fcc-codex` shared generic adapter plumbing. |
`fcc-claude` and `fcc-codex` use explicit launcher modules. |
| Messaging depended on a generic CLI session abstraction. | Messaging
depends on managed Claude Code sessions. |
| Codex catalog generation lived as a top-level CLI helper. | Codex
catalog generation lives under the Codex launcher owner. |
| Tests asserted deleted internal adapter shapes. | Tests assert
launcher, managed-Claude, and customer-surface behavior. |
Consolidates the incremental refactor work into a single change set: modular web tools (api/web_tools), native Anthropic request building and SSE block policy, OpenAI conversion and error handling, provider transports and rate limiting, messaging handler and tree queue, safe logging, smoke tests, and broad test coverage.
The max_sessions cap in CLISessionManager was the only thing enforcing
a limit on concurrent CLI processes. Now that provider concurrency is
controlled at the streaming layer (PROVIDER_MAX_CONCURRENCY semaphore),
the CLI session pool cap is redundant and removed entirely.
Changes:
- cli/manager.py: remove max_sessions param, cap check, _cleanup_idle_sessions_unlocked, max_sessions from get_stats()
- config/settings.py: remove max_cli_sessions field
- api/app.py: remove max_sessions=settings.max_cli_sessions from CLISessionManager constructor
- messaging/handler.py: remove "Waiting for slot" status check; stats display no longer shows Max CLI
- .env.example: remove MAX_CLI_SESSIONS line
- tests/cli/test_cli.py: remove max_sessions args and assertion from manager tests
- tests/cli/test_cli_manager_edge_cases.py: remove two tests for cap/cleanup behavior
- tests/api/test_app_lifespan_and_errors.py: remove max_cli_sessions from all SimpleNamespace settings
- tests/config/test_config.py: remove max_cli_sessions isinstance assertion
- tests/conftest.py: remove max_sessions from mock stats
- tests/messaging/test_handler.py: merge slot/capacity tests into single new-conversation test; remove Max CLI assertion from stats test
- tests/messaging/test_handler_markdown_and_status_edges.py: remove "Waiting for slot" assertion; drop max_sessions from all stats mocks
https://claude.ai/code/session_014mrF1WMNgmNjtPBuoQHsbg