文件历史

38 次代码提交

作者 SHA1 备注 提交日期
Ali Khokhar 5305bd7e08 Remove obsolete init and server alias commands (#1220)
## Problem

FCC still publishes `fcc-init` and the `free-claude-code` server alias
from an obsolete installation flow. Configuration creation now belongs
to the Admin UI, while `fcc-server` owns startup and legacy migration.

## Changes

| Before | After |
| --- | --- |
| The package installs six console commands. | The package installs only
`fcc-server`, `fcc-claude`, `fcc-codex`, and `fcc-pi`. |
| `fcc-init` duplicates configuration creation outside the Admin UI. |
The Admin UI exclusively creates managed configuration, and server
startup retains legacy migration. |
| Smoke contracts and architecture describe the retired commands. |
Smoke contracts and architecture describe the supported command surface.
|
| Installer safety lists contain unexplained retired names. | Installer
safety lists document why retired names remain detectable during updates
and uninstall. |
| The package version is `4.11.4`. | The package version is `4.11.5`. |

<!-- greptile_comment -->

<details open><summary><h3>Greptile Summary</h3></summary>

This PR retires the obsolete initialization command and server alias.
The main changes are:

- Removes `fcc-init` and `free-claude-code` from package scripts.
- Moves fresh configuration creation exclusively to the Admin UI.
- Keeps legacy environment migration in `fcc-server` startup.
- Updates smoke coverage, installer comments, documentation, and package
metadata.
</details>

<h3>Confidence Score: 4/5</h3>

The CLI removal needs a compatible release version or temporary aliases
before merging.

Existing automation can lose `fcc-init` and `free-claude-code` after a
patch upgrade. Fresh installs can still start the server and create
configuration through the Admin UI.

pyproject.toml and uv.lock; legacy configuration migration remains
before settings loading.

<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**
- I reproduced the patch upgrade path by installing base revision
d37b34b02f in an isolated Python 3.14
environment and verified that fcc-init --version and free-claude-code
--version reported 4.11.4 with exit code 0. After upgrading to head
revision 9a65f654f5e06c0ca96a31d3ad03db8c63d8dec7, the installed version
changed to 4.11.5 and both entrypoints disappeared, with subsequent
invocations yielding command-not-found errors (exit code 127).
- Local smoke tests and server migrations completed successfully: the
CLI local smoke test exited with code 0, the installed-entrypoints
checks passed, and the server migrated to a healthy state with the
health endpoint responding.

<a
href="https://app.greptile.com/trex/runs/15196662/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 | Removes two public console commands while applying a
patch version bump. |
| src/free_claude_code/cli/commands.py | Removes template-based
initialization while preserving startup migration. |
| src/free_claude_code/cli/entrypoints.py | Removes the retired
initialization entrypoint and retains server version handling. |
| smoke/lib/child_process.py | Removes the init helper and renames the
server helper consistently. |
| scripts/install.sh | Keeps retired names in process detection for safe
upgrades. |
| scripts/uninstall.sh | Keeps retired names in removal checks for older
installations. |
| uv.lock | Tracks the patch version that must change if the command
removal remains breaking. |

</details>

<a
href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22alishahryar1%2Ffree-claude-code%22%20on%20the%20existing%20branch%20%22remove-obsolete-cli-commands%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22remove-obsolete-cli-commands%22.%0A%0AFix%20the%20following%201%20code%20review%20issue.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%201%0Apyproject.toml%3A7%0A**Breaking%20Commands%20Ship%20as%20Patch**%0A%0AUpgrading%20from%204.11.4%20removes%20the%20published%20%60fcc-init%60%20and%20%60free-claude-code%60%20commands%2C%20so%20existing%20scripts%20fail%20with%20%E2%80%9Ccommand%20not%20found.%E2%80%9D%20The%20repository%20policy%20classifies%20incompatible%20CLI%20removals%20as%20major%20changes%3B%20keep%20compatibility%20aliases%20for%204.x%20or%20publish%20this%20removal%20as%205.0.0.%0A%0A&repo=alishahryar1%2Ffree-claude-code&pr=1220&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodexDark.svg?v=6"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"><img
alt="Fix All in Codex"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"></picture></a>

<sub>Reviews (1): Last reviewed commit: ["Remove obsolete CLI entry
points"](https://github.com/alishahryar1/free-claude-code/commit/9a65f654f5e06c0ca96a31d3ad03db8c63d8dec7)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=45848525)</sub>

> Greptile also left **1 inline comment** on this PR.

<!-- /greptile_comment -->
2026-07-20 21:55:49 -07:00
Ali Khokhar af12e7b2bb Coordinate provider recovery under concurrent load (#1205)
## Problem

Concurrent transient failures could start independent retry, replay,
continuation, and repair loops while holding provider concurrency slots.
This multiplied upstream attempts and could delay or strand terminal
errors under fan-out.

## Changes

| Before | After |
| --- | --- |
| Retry paths owned separate attempt budgets. | One logical-execution
session caps all upstream work at five attempts. |
| Concurrent failures backed off independently. | One provider-owned
recovery episode elects a single half-open probe while followers
coalesce. |
| Backoff occupied stream concurrency. | Concurrency is held only while
an upstream operation or stream is active. |
| Provider catalog calls and stream creation used separate admission
paths. | Every upstream operation uses one provider-generation admission
controller. |
| Cancellation could leave recovery ownership or follower state
unresolved. | Cancellation releases permits, transfers probe ownership,
and unregisters waiting followers. |
| Late in-flight failures could cross an exhausted episode boundary. |
Every coalesced execution retains that generation's terminal outcome. |
| Replay tests allowed loose lifecycle assertions. | Exact SSE contracts
prove retries and continuations emit one unduplicated response. |
| Recovery wrappers could mask final diagnostics. | Final responses and
traces retain the raw provider failure and request ID. |

<!-- greptile_comment -->

<details open><summary><h3>Greptile Summary</h3></summary>

This PR coordinates provider recovery and retry work under concurrent
load. The main changes are:

- One five-attempt budget for each logical execution.
- Provider-wide recovery episodes with one elected probe.
- Shared admission for streams, catalog calls, rate limits, and
concurrency.
- Concurrency permits held only during active upstream work.
- Cancellation-safe probe ownership and preserved final diagnostics.
</details>

<h3>Confidence Score: 5/5</h3>

This looks safe to merge.

No blocking issues found in the changed code.

<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 coordinated-recovery-01-before.log to understand how the
exhausted generation outcome was not preserved in a late in-flight
failure.
- Reviewed the coordinated-recovery-02-after.log to confirm that the
updated implementation preserves the exhausted generation outcome for
the same focused contract set.
- Validated that the provider-admission-full-current.log shows the
complete requested test file passed under Python 3.14 with uv run pytest
-n 0.

<a
href="https://app.greptile.com/trex/runs/15050270/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/providers/admission.py | Adds shared admission,
retry budgets, recovery episodes, probe election, and cancellation
handling. |
| src/free_claude_code/providers/openai_chat/provider.py | Moves stream
creation, replay, continuation, and repair onto one admission-owned
retry session. |
| src/free_claude_code/providers/stream_recovery.py | Selects replay,
continuation, repair, or final failure using the remaining shared
attempt budget. |
| src/free_claude_code/providers/failure_policy.py | Adds recovery
exhaustion handling and preserves the underlying provider error for
final classification. |
| src/free_claude_code/providers/runtime/factory.py | Creates one
admission controller per provider generation and passes it through
provider factories. |

</details>

<details open><summary><h3>Sequence Diagram</h3></summary>

<a href="#gh-light-mode-only">

```mermaid
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant E as Execution
participant A as Admission controller
participant P as Provider
participant F as Concurrent follower

E->>A: Open attempt
A->>P: Send upstream request
P-->>E: Retryable failure
E->>A: Open recovery episode
F->>A: Request admission
A-->>F: Coalesce and wait
E->>A: Claim probe
A->>P: Send half-open probe
alt Probe succeeds
    P-->>E: Valid response
    E->>A: Close recovery episode
    A-->>F: Release waiter
else Probe fails
    P-->>E: Retryable failure
    E->>A: Schedule next probe or finalize error
end
```

</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 E as Execution
participant A as Admission controller
participant P as Provider
participant F as Concurrent follower

E->>A: Open attempt
A->>P: Send upstream request
P-->>E: Retryable failure
E->>A: Open recovery episode
F->>A: Request admission
A-->>F: Coalesce and wait
E->>A: Claim probe
A->>P: Send half-open probe
alt Probe succeeds
    P-->>E: Valid response
    E->>A: Close recovery episode
    A-->>F: Release waiter
else Probe fails
    P-->>E: Retryable failure
    E->>A: Schedule next probe or finalize error
end
```

</a>
</details>

<sub>Reviews (2): Last reviewed commit: ["Harden coordinated retry
lifecycle
invar..."](https://github.com/alishahryar1/free-claude-code/commit/2e871c8649d148b5eb71d21f80bf870ae2d11708)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=45554917)</sub>

<!-- /greptile_comment -->
2026-07-19 22:43:29 -07:00
Ali Khokhar 6455c63e1d Make reasoning policy provider-neutral and client-aware (#1148)
## Problem

FCC reduced reasoning to global and route booleans, mixing client
intent, configuration, provider wire capabilities, output visibility,
and history replay. That discarded named client efforts, encouraged
model-name checks, and made provider behavior inconsistent.

## Changes

| Before | After |
| --- | --- |
| Admin exposed global and route thinking toggles. | Admin exposes
**Off**, **From client**, **Low**, **Medium**, **High**, **X-High**, and
**Max**; Fable, Opus, Sonnet, and Haiku also expose **Inherit**. |
| Request intent was repeatedly reduced to a boolean across routing and
providers. | The application boundary resolves one immutable
`ReasoningPolicy` with independent control, named effort, and exact
positive token budget. |
| Provider adapters could infer reasoning behavior from upstream model
names or versions. | Provider profiles translate only documented
provider-wide wire capabilities; architecture and contributor rules
prohibit model-specific reasoning branches. |
| Gateway reasoning controls were ad hoc. |
[OpenRouter](https://openrouter.ai/docs/guides/best-practices/reasoning-tokens)
and [Vercel AI
Gateway](https://vercel.com/docs/ai-gateway/models-and-providers) use
documented reasoning objects, including exact budgets where
representable. |
| Named effort forwarding was inconsistent or absent. |
[Gemini](https://ai.google.dev/gemini-api/docs/openai),
[Ollama](https://docs.ollama.com/api/openai-compatibility), [LM
Studio](https://lmstudio.ai/changelog/lmstudio-v0.4.8),
[Fireworks](https://docs.fireworks.ai/guides/querying-text-models/reasoning),
[Cohere](https://docs.cohere.com/docs/compatibility-api),
[Wafer](https://docs.wafer.ai/serverless/api-reference),
[Groq](https://console.groq.com/docs/reasoning),
[Cerebras](https://inference-docs.cerebras.ai/capabilities/reasoning),
[SambaNova](https://docs.sambanova.ai/docs/api-reference/chat-completions/create-chat-based-completion),
and
[Mistral](https://docs.mistral.ai/studio-api/conversations/reasoning)
receive their documented named vocabularies with explicit provider-owned
downgrades. |
| Boolean thinking controls were mixed into shared conversion. |
[DeepSeek](https://api-docs.deepseek.com/guides/thinking_mode/),
[Kimi](https://platform.kimi.ai/docs/guide/use-kimi-k2-thinking-model),
[Z.ai](https://docs.z.ai/guides/capabilities/thinking-mode), [Cloudflare
Workers
AI](https://developers.cloudflare.com/changelog/post/2026-04-20-kimi-k2-6-workers-ai/),
and [NVIDIA
NIM](https://docs.nvidia.com/nim/large-language-models/1.15.0/thinking-budget-control.html)
use provider-owned thinking-object or chat-template controls. |
| Effort names and output limits could become fabricated reasoning
budgets. | Exact budgets remain exact and are forwarded only through
documented fields for OpenRouter, Fireworks, LM Studio, NIM, and
[llama.cpp](https://github.com/ggml-org/llama.cpp/blob/master/tools/server/README.md);
named efforts and output limits are never converted into token budgets.
|
| New-turn reasoning and prior-turn replay shared one switch. | Every
profile independently declares native reasoning replay, `<think>` tag
replay, provider-specific replay, or no replay; **Off** suppresses new
reasoning output without corrupting required history. |
| Providers without a stable generic compute control received guessed
controls. |
[MiniMax](https://platform.minimax.io/docs/api-reference/text-openai-api)
requests split output only, while [GitHub
Models](https://docs.github.com/en/rest/models/inference), [Hugging Face
Inference
Providers](https://huggingface.co/docs/inference-providers/en/tasks/chat-completion),
Codestral, and OpenCode keep provider defaults and use only their
explicit replay profile. |
| OpenAI Responses effort became a lossy Anthropic thinking boolean. |
Responses preserves `reasoning.effort` through `output_config`, then
resolves it through the same application policy as Messages without
inventing a budget. |
| Legacy booleans remained the persisted contract. | FCC-owned dotenv
files migrate to typed `REASONING_*` values, explicit env files receive
an actionable warning, documentation describes the ownership boundary,
and the package advances to 4.8.0. |
| Reasoning behavior was covered by scattered boolean assertions. | New
policy, routing, encoder, provider, Admin, migration, Responses, and
smoke contracts pass all five local CI checks: 2,368 tests passed, 40
skipped; 92 smoke tests collect and both live config migration checks
pass. |

<!-- greptile_comment -->

<details open><summary><h3>Greptile Summary</h3></summary>

This PR makes reasoning policy client-aware and independent of provider
model names. The main changes are:

- Adds one immutable reasoning policy resolved at the application
boundary.
- Adds typed root and route reasoning settings with Admin UI support.
- Moves wire controls and history replay behavior into provider
profiles.
- Migrates owned dotenv files from legacy thinking booleans.
- Expands provider, routing, migration, API, and smoke coverage.
</details>

<h3>Confidence Score: 5/5</h3>

This looks safe to merge.

No blocking issues found in the changed code.

<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**
- Ran the contract-validation test suite with the specified test
modules, and the tests reported 78 passed in 1.53s with exit code 0.
- Reviewed the complete captured output artifact
reasoning-contract-02-after.log to verify the final test outcomes and
successful contract validation.

<a
href="https://app.greptile.com/trex/runs/14792858/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/config/env_migrations.py | Migrates legacy
reasoning booleans in owned dotenv files and warns for explicit
environment files. |
| src/free_claude_code/application/reasoning.py | Resolves client
controls and configured preferences into one provider-neutral reasoning
policy. |
| src/free_claude_code/application/routing.py | Carries route-level
reasoning preferences into request-scoped policy resolution. |
| src/free_claude_code/providers/openai_chat/reasoning.py | Provides
shared provider encoders for reasoning controls and replay behavior. |

</details>

<sub>Reviews (2): Last reviewed commit: ["chore: release reasoning
controls as
4.8..."](https://github.com/alishahryar1/free-claude-code/commit/9d4be767f7dbdca5709474012f43dcdc6f4347e3)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=44984039)</sub>

<!-- /greptile_comment -->
2026-07-16 19:57:12 -07:00
Ali Khokhar 4f56a6aa17 Add Fable as a first-class Claude routing tier (#1099)
## Problem

Claude Code now sends `claude-fable-5` for the Fable alias, but FCC
treated it as an unrecognized model and collapsed it into the global
fallback route. Users could not map Fable traffic or reasoning behavior
independently. Fixes #1097.

## Changes

| Before | After |
| --- | --- |
| Fable requests inherited `MODEL` and `ENABLE_MODEL_THINKING`. | Fable
requests use `MODEL_FABLE` and `ENABLE_FABLE_THINKING` when configured,
otherwise inherit the existing defaults. |
| `/v1/models` omitted Claude Fable 5. | `/v1/models` advertises the
canonical `claude-fable-5` identifier. |
| Admin, documentation, validation, and smoke contracts described three
Claude tiers. | Admin, documentation, validation, and smoke contracts
describe Fable alongside Opus, Sonnet, and Haiku. |
| The package version was `4.3.1`. | The package version is `4.4.0`. |

<!-- greptile_comment -->

<details open><summary><h3>Greptile Summary</h3></summary>

This PR adds Fable as a Claude routing tier. The main changes are:

- `MODEL_FABLE` and `ENABLE_FABLE_THINKING` settings.
- Fable routing and thinking resolution in `ModelRouter`.
- `claude-fable-5` in the model catalog.
- Admin, docs, smoke, and test coverage updates.
- Package version bump to `4.4.0`.
</details>

<h3>Confidence Score: 4/5</h3>

The changed routing path needs a fix for direct provider model ids
containing `fable`.

Fable settings, validation, admin fields, and model listing are
consistent with the existing tier patterns. Blank Fable settings inherit
the existing defaults. Direct provider model ids can receive the Fable
thinking override when their model name contains `fable`.

src/free_claude_code/application/routing.py

<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**
- Reproduced the Fable thinking overmatch by running a focused Python
repro that disables global thinking and enables Fable thinking, then
resolves sambanova/my-fable-ensemble-v2.
- The repro confirmed direct routing preserved provider\_id=sambanova,
provider\_model=my-fable-ensemble-v2, and
provider\_model\_ref=sambanova/my-fable-ensemble-v2, with
resolved\_thinking\_enabled and thinking\_enabled both true.
- Ran the fable-tier validation pytest, which finished with exit code 0
and 177 tests passed.
- Ran the runtime probe to exercise the API model list, Settings env
parsing, and ModelRouter paths, and observed a 200 OK on GET /v1/models,
with the catalog item id claude-fable-5 and the expected Fable vs
global-default routing behavior.
- Generated the probe source file used to exercise the API and Settings
paths, enabling repeatable validation without real provider credentials.

<a
href="https://app.greptile.com/trex/runs/14275379/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/application/routing.py | Adds Fable model and
thinking branches; the thinking branch can also match unrelated direct
provider model ids containing `fable`. |
| src/free_claude_code/config/settings.py | Adds optional Fable model
and thinking settings with blank-env inheritance and provider/model
validation. |
| src/free_claude_code/config/model_refs.py | Includes Fable in
configured chat model reference collection and dedupe. |
| src/free_claude_code/config/admin/manifest.py | Adds Fable model and
thinking controls to the admin manifest. |
| src/free_claude_code/api/model_catalog.py | Adds `claude-fable-5` to
the advertised Claude model aliases. |
| pyproject.toml | Bumps the package version to `4.4.0`. |
| uv.lock | Updates the editable package version to match
`pyproject.toml`. |

</details>

<details open><summary><h3>Flowchart</h3></summary>

<a href="#gh-light-mode-only">

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Incoming model name] --> B{Direct provider or gateway id?}
  B -- yes --> C[Use provider/model directly]
  C --> D[Resolve thinking from provider model string]
  B -- no --> E{Claude tier match}
  E -- Fable --> F[MODEL_FABLE or MODEL]
  E -- Opus/Sonnet/Haiku --> G[Tier override or MODEL]
  E -- None --> H[MODEL]
  D --> I[Provider request]
  F --> I
  G --> I
  H --> I
```

</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"}}}%%
flowchart TD
  A[Incoming model name] --> B{Direct provider or gateway id?}
  B -- yes --> C[Use provider/model directly]
  C --> D[Resolve thinking from provider model string]
  B -- no --> E{Claude tier match}
  E -- Fable --> F[MODEL_FABLE or MODEL]
  E -- Opus/Sonnet/Haiku --> G[Tier override or MODEL]
  E -- None --> H[MODEL]
  D --> I[Provider request]
  F --> I
  G --> I
  H --> I
```

</a>
</details>

<a
href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22alishahryar1%2Ffree-claude-code%22%20on%20the%20existing%20branch%20%22ali%2Fadd-fable-routing-tier%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22ali%2Fadd-fable-routing-tier%22.%0A%0AFix%20the%20following%201%20code%20review%20issue.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%201%0Asrc%2Ffree_claude_code%2Fapplication%2Frouting.py%3A134-135%0A**Fable%20Thinking%20Overmatches%20Models**%0A%0AWhen%20a%20direct%20provider%20request%20uses%20a%20model%20id%20like%20%60sambanova%2Fmy-fable-ensemble-v2%60%2C%20the%20direct%20route%20bypasses%20tier%20remapping%20but%20still%20calls%20%60_resolve_thinking%28%29%60%20with%20the%20provider%20model%20string.%20With%20%60ENABLE_FABLE_THINKING%60%20set%2C%20this%20substring%20check%20applies%20Fable%20thinking%20behavior%20to%20an%20unrelated%20provider%20model%2C%20changing%20the%20outgoing%20request%20shape%20just%20because%20the%20model%20id%20contains%20%60fable%60.%0A%0A&repo=alishahryar1%2Ffree-claude-code&pr=1099&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodexDark.svg?v=6"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"><img
alt="Fix All in Codex"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"></picture></a>

<sub>Reviews (1): Last reviewed commit: ["Add Fable as a first-class
routing
tier"](https://github.com/alishahryar1/free-claude-code/commit/0705840c65511fd85c74fd2c62ba8ea97afe7c12)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=43892323)</sub>

> Greptile also left **1 inline comment** on this PR.

<!-- /greptile_comment -->
2026-07-13 11:56:34 -07:00
Ali Khokhar 0d5bec3dcd Make proxy authentication bearer-only across every client (#1096)
## Problem

Proxy authentication selected the first of three credential headers, so
a stale `X-API-Key` could mask valid bearer authorization and leave
Claude CLI or IDE clients at their login gate. Fixes #902.

## Changes

| Before | After |
| --- | --- |
| FCC accepted three proxy credential headers and stripped legacy model
suffixes. | FCC accepts one exact `Authorization: Bearer` token without
mutation. |
| Conflicting provider credentials could override valid proxy
authorization. | Unrelated credential headers are ignored during proxy
authentication. |
| Codex catalog discovery and Pi catalog or inference paths used API-key
authentication. | Every FCC-owned Codex and Pi path uses bearer
authorization. |
| Authentication failures referred ambiguously to an API key. |
Authentication failures identify the proxy authentication token. |
| FCC reported version `4.2.0`. | FCC reports version `4.3.0`. |

<!-- greptile_comment -->

<details open><summary><h3>Greptile Summary</h3></summary>

This PR makes proxy authentication use bearer tokens only. The main
changes are:

- Replaced multi-header proxy auth with exact `Authorization: Bearer
<token>` checks.
- Updated protected route dependencies to use the renamed auth
dependency.
- Switched FCC-owned Codex and Pi catalog requests to bearer
authorization.
- Added Pi provider `authHeader` registration for inference requests.
- Updated smoke tests, API tests, docs, examples, and package metadata
for the new auth contract.
</details>

<h3>Confidence Score: 4/5</h3>

The changed auth flow is mostly consistent, but Codex inference can
still fail if its generated provider config sends API-key auth.

Server-side bearer parsing is direct and covered by updated tests. Route
protection appears preserved after the dependency rename. Codex catalog
auth was updated, but the inference path still depends on external
client header behavior. The version bump may understate a breaking
auth-contract change.

src/free_claude_code/api/dependencies.py,
src/free_claude_code/cli/launchers/codex.py, pyproject.toml

<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**
- T-Rex executed targeted proxy authentication validation to verify
bearer token behavior before and after the change.
- T-Rex compared pre-change and post-change test results, confirming 31
passed before and 39 passed after, and validating HTTP 200 for exact
bearer with unrelated X-API-Key plus HTTP 401 for missing or invalid
tokens.

<a
href="https://app.greptile.com/trex/runs/14225355/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/api/dependencies.py | Replaces proxy
authentication with exact bearer-token validation and new error details.
|
| src/free_claude_code/api/routes.py | Updates protected route
dependencies to call the renamed auth dependency. |
| src/free_claude_code/cli/launchers/codex.py | Changes Codex catalog
discovery to send bearer auth while leaving inference auth delegated
through Codex config. |
| src/free_claude_code/cli/launchers/pi_extension.ts | Changes Pi
catalog discovery to bearer auth and registers the provider with
`authHeader` enabled. |
| smoke/lib/config.py | Updates smoke helper auth headers to emit bearer
authorization. |
| pyproject.toml | Bumps the package version from 4.2.0 to 4.3.0. |

</details>

<details open><summary><h3>Sequence Diagram</h3></summary>

<a href="#gh-light-mode-only">

```mermaid
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant Codex
participant Launcher as FCC Codex launcher
participant API as FCC API
Launcher->>API: GET /v1/models with Authorization Bearer token
API-->>Launcher: Catalog response
Launcher-->>Codex: Raw token in FCC_CODEX_API_KEY
Codex->>API: POST /v1/responses with client-built auth
alt Client sends bearer authorization
    API-->>Codex: Accepted
else Client sends API-key auth
    API-->>Codex: 401 proxy auth failure
end
```

</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 Codex
participant Launcher as FCC Codex launcher
participant API as FCC API
Launcher->>API: GET /v1/models with Authorization Bearer token
API-->>Launcher: Catalog response
Launcher-->>Codex: Raw token in FCC_CODEX_API_KEY
Codex->>API: POST /v1/responses with client-built auth
alt Client sends bearer authorization
    API-->>Codex: Accepted
else Client sends API-key auth
    API-->>Codex: 401 proxy auth failure
end
```

</a>
</details>

<a
href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22alishahryar1%2Ffree-claude-code%22%20on%20the%20existing%20branch%20%22ali%2Fcanonical-proxy-bearer-auth%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22ali%2Fcanonical-proxy-bearer-auth%22.%0A%0AFix%20the%20following%202%20code%20review%20issues.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%202%0Asrc%2Ffree_claude_code%2Fapi%2Fdependencies.py%3A56%0A**Codex%20Inference%20Still%20Delegates%20Auth**%0A%0AWhen%20Codex%20launches%2C%20FCC%20now%20sends%20bearer%20auth%20only%20for%20its%20own%20%60%2Fv1%2Fmodels%60%20catalog%20request%2C%20but%20inference%20still%20depends%20on%20Codex%20turning%20the%20raw%20%60FCC_CODEX_API_KEY%60%20value%20into%20the%20same%20bearer%20header.%20If%20Codex%20sends%20that%20env%20key%20as%20an%20API-key%20header%2C%20this%20server%20branch%20treats%20the%20request%20as%20missing%20proxy%20auth%20and%20%60%2Fv1%2Fresponses%60%20fails%20with%20401%20even%20though%20catalog%20discovery%20succeeded.%0A%0A%23%23%23%20Issue%202%20of%202%0Apyproject.toml%3A7%0A**Breaking%20Auth%20Contract%20Understated**%0A%0AThis%20change%20removes%20previously%20accepted%20proxy%20credential%20shapes%2C%20including%20%60X-API-Key%60%2C%20%60anthropic-auth-token%60%2C%20and%20suffixed%20bearer%20tokens%2C%20but%20the%20package%20version%20only%20moves%20from%20%604.2.0%60%20to%20%604.3.0%60.%20Existing%20users%20can%20upgrade%20within%20the%20same%20major%20line%20and%20have%20every%20protected%20endpoint%20start%20returning%20401%20until%20their%20clients%20are%20reconfigured%2C%20which%20does%20not%20match%20the%20repository%20guidance%20for%20incompatible%20API%20or%20CLI%20behavior.%0A%0A&repo=alishahryar1%2Ffree-claude-code&pr=1096&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodexDark.svg?v=6"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"><img
alt="Fix All in Codex"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"></picture></a>

<sub>Reviews (1): Last reviewed commit: ["fix: make proxy auth
bearer-only"](https://github.com/alishahryar1/free-claude-code/commit/c437ee0e23dc8f8411272a8dcfcf1ff69f315857)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=43791345)</sub>

> Greptile also left **2 inline comments** on this PR.

**Context used:**

- Context used - CLAUDE.md
([source](https://app.greptile.com/alishahryar1/github/Alishahryar1/free-claude-code/-/custom-context?memory=d2fd24d8-0dec-4faf-8ee4-e085e215a2f8))

<!-- /greptile_comment -->
2026-07-13 04:26:20 -07:00
Ali Khokhar 2fe2ba82d2 Add Pi as a first-class FCC client (#1088)
## Problem

FCC had no first-class Pi path, so Pi users had to maintain provider
configuration themselves. FCC's installers and ownership docs also
covered only Claude Code and Codex.

## Changes

| Before | After |
| --- | --- |
| Pi required persistent user-managed provider configuration. | `fcc-pi`
registers an ephemeral FCC provider from the live model catalog and
leaves Pi-owned state untouched. |
| Client launchers normalized blank proxy authentication separately. |
Claude, Codex, and Pi share one neutral proxy-auth policy. |
| FCC installers and uninstallers did not account for Pi. | Installers
delegate missing Pi setup to its official platform installer, while
uninstallers remove only `fcc-pi` and preserve native Pi. |
| Pi compatibility had no executable FCC contract. | Deterministic
launcher and lifecycle coverage plus a real Pi 0.80.6 smoke verify model
discovery and `/v1/messages` end to end. |

<!-- greptile_comment -->

<details open><summary><h3>Greptile Summary</h3></summary>

This PR adds Pi as a supported FCC client. The main changes are:

- A new `fcc-pi` launcher and bundled Pi extension.
- Shared proxy-auth handling for client launchers.
- Pi installation, verification, and uninstall coverage in platform
scripts.
- Pi-focused tests, smoke coverage, and user documentation.
</details>


<h3>Confidence Score: 5/5</h3>

This looks safe to merge.

No blocking issues found in the changed code.

None.

<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**
- Ran the targeted pytest command and confirmed deterministic success
with 27 passed in 2.68s and EXIT\_CODE: 0.
- Analyzed the blocker log and determined that Pi CLI and live-smoke
prerequisites are missing, blocking external Pi execution; uv is
available and provider smoke models are discoverable, narrowing the
issue to Pi CLI plus live-smoke opt-in.

<a
href="https://app.greptile.com/trex/runs/14192651/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/launchers/pi.py | Adds the `fcc-pi` launcher,
Pi capability checks, passthrough handling, extension loading, and
FCC-scoped environment setup. |
| src/free_claude_code/cli/launchers/pi_extension.ts | Adds the Pi
extension that fetches FCC models and registers a process-local
Anthropic Messages provider. |
| scripts/install.sh | Adds Pi install, PATH refresh, capability
verification, and `fcc-pi` command checks for POSIX installs. |
| scripts/install.ps1 | Adds Pi install, PATH refresh, capability
verification, and `fcc-pi` command checks for Windows installs. |
| pyproject.toml | Registers the `fcc-pi` console script and bumps the
package version. |

</details>


<!-- greptile_failed_comments -->
<h3>Comments Outside Diff (1)</h3>

1. General comment 

<a href="#"><img alt="P1"
src="https://greptile-static-assets.s3.amazonaws.com/badges/p1.svg?v=9"
align="top"></a> **Pi entrypoint contract test fails due install-hint
mismatch**

   - **Bug**
- The narrow Pi launcher/entrypoint test selection fails on current
HEAD. `test_launch_pi_rejects_unrelated_pi_binary` expects stderr to
include the Windows PowerShell install URL `https://pi.dev/install.ps1`,
but the launcher emitted the POSIX install command `curl -fsSL
https://pi.dev/install.sh | sh` in this Linux sandbox.
   - **Cause**
- The Pi launcher's incompatible-binary error path and the test contract
disagree about which platform-specific install hint should be emitted
for this scenario.
   - **Fix**
- Align the Pi launcher contract with the test expectation: either
update the launcher to emit the expected platform-specific hint for the
mocked scenario, or update the test to assert the correct hint for the
active/mocked platform. Then rerun `uv run --frozen pytest -q
tests/cli/test_entrypoints.py -k 'pi'`.

<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>
<!-- /greptile_failed_comments -->

<sub>Reviews (3): Last reviewed commit: ["Add first-class Pi client
integration"](https://github.com/alishahryar1/free-claude-code/commit/cd5c335f8cf2dee93d927496d7cabbffec86f169)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=43721088)</sub>

<!-- /greptile_comment -->
2026-07-12 20:54:57 -07:00
Ali Khokhar 3fba1c6fc3 Give messaging clear exact subtree semantics (#1072)
## Problem

Messaging `/clear` did not follow the selected platform message
boundary. Reply clears preserved the selected user prompt, while
standalone clears preserved user-authored messages and could reset FCC
state outside the invoking chat.

## Changes

| Before | After |
| --- | --- |
| Reply `/clear` removed a logical conversation branch but retained the
selected message. | Reply `/clear` deletes the selected message and its
literal reply subtree, including the clear command. |
| Standalone `/clear` retained user prompts and voice notes while
resetting global messaging state. | Standalone `/clear` deletes every
tracked message and resets FCC state only in the invoking platform and
chat. |
| Trees recorded only logical execution parentage. | Trees separately
persist logical execution ancestry and exact prompt/status reply
ownership. |
| Clear coordination used one global admission boundary. | Per-chat
clear generations coordinate admission, voice cancellation, persistence,
and best-effort platform deletion. |
| Persistence tracked only FCC-authored clearable output. | Persistence
tracks managed inbound and outbound messages and migrates legacy
entries. |

<!-- greptile_comment -->

<details open><summary><h3>Greptile Summary</h3></summary>

This PR gives messaging `/clear` exact per-chat and reply-subtree
behavior. The main changes are:

- Per-chat clear generations for admission and startup-notice cleanup.
- Managed inbound and outbound message tracking for deletion.
- Exact prompt/status reply ownership in message trees.
- Scoped voice cancellation and clear persistence updates.
- Updated docs, smoke coverage, and messaging tests.
</details>

<h3>Confidence Score: 4/5</h3>

The clear flow is mostly well-contained, with one upgrade-path issue in
legacy tree restoration.

Newly created prompt/status subtrees use the new exact reference fields
consistently, and legacy snapshots can map old status replies to prompt
references. However, reply `/clear` on an upgraded status can miss
descendants and leave stale state/messages.

src/free_claude_code/messaging/trees/snapshot.py

<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**
- T-Rex attempted to prepare and run a focused legacy snapshot
reproduction harness for legacy status replies detach, but tool access
was blocked before execution.
- A messaging clear smoke test harness was executed and reported a
passing result: 20 items collected and 20 passed in 1.69 seconds, with
traces for test\_reply\_clear\_uses\_literal and related paths shown in
the log.

<a
href="https://app.greptile.com/trex/runs/14131337/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/messaging/workflow.py | Adds per-chat clear
generations, managed inbound recording, scoped clears, and
startup-notice invalidation. |
| src/free_claude_code/messaging/trees/graph.py | Adds exact
prompt/status reference resolution and literal reply-subtree traversal.
|
| src/free_claude_code/messaging/trees/runtime.py | Adds exact
message-subtree removal and status-only clearing behavior. |
| src/free_claude_code/messaging/trees/snapshot.py | Adds
parent_reference_id persistence and legacy fallback; the fallback can
miss legacy status-reply descendants. |
| src/free_claude_code/messaging/session/managed_message_log.py |
Replaces the clearable output log with managed inbound and outbound
message tracking. |
| src/free_claude_code/messaging/commands.py | Routes reply and
standalone `/clear` through the new exact deletion ID flows. |

</details>

<details open><summary><h3>Flowchart</h3></summary>

<a href="#gh-light-mode-only">

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Incoming message] --> B{Standalone /clear?}
B -- yes --> C[Clear invoking chat]
C --> D[Cancel scoped voice work]
C --> E[Collect managed and tree message IDs]
C --> F[Advance chat clear generation]
F --> G[Detach scoped trees]
G --> H[Clear scoped session store]
H --> I[Best-effort platform deletes]
B -- no --> J[Record managed inbound message]
J --> K[Admit with stop and clear token]
K --> L{Reply /clear?}
L -- yes --> M[Resolve exact prompt or status reference]
M --> N[Remove literal reference subtree]
N --> I
L -- no --> O[Queue or run tree node]
```

</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"}}}%%
flowchart TD
A[Incoming message] --> B{Standalone /clear?}
B -- yes --> C[Clear invoking chat]
C --> D[Cancel scoped voice work]
C --> E[Collect managed and tree message IDs]
C --> F[Advance chat clear generation]
F --> G[Detach scoped trees]
G --> H[Clear scoped session store]
H --> I[Best-effort platform deletes]
B -- no --> J[Record managed inbound message]
J --> K[Admit with stop and clear token]
K --> L{Reply /clear?}
L -- yes --> M[Resolve exact prompt or status reference]
M --> N[Remove literal reference subtree]
N --> I
L -- no --> O[Queue or run tree node]
```

</a>
</details>

<a
href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22alishahryar1%2Ffree-claude-code%22%20on%20the%20existing%20branch%20%22ali%2Fclear-message-subtree%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22ali%2Fclear-message-subtree%22.%0A%0AFix%20the%20following%201%20code%20review%20issue.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%201%0Asrc%2Ffree_claude_code%2Fmessaging%2Ftrees%2Fsnapshot.py%3A192-193%0A**Legacy%20Status%20Replies%20Detach**%0A%0AWhen%20an%20upgraded%20legacy%20snapshot%20contains%20a%20child%20that%20originally%20replied%20to%20its%20parent%20status%2C%20this%20fallback%20rewrites%20the%20missing%20exact%20reference%20to%20the%20parent%20prompt.%20A%20later%20reply%20%60%2Fclear%60%20on%20that%20status%20traverses%20from%20the%20status%20ID%2C%20finds%20no%20migrated%20child%20edge%2C%20and%20leaves%20the%20old%20status-reply%20descendants%20and%20their%20managed%20messages%20behind.%0A%0A&repo=alishahryar1%2Ffree-claude-code&pr=1072&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodexDark.svg?v=6"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"><img
alt="Fix All in Codex"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"></picture></a>

<sub>Reviews (1): Last reviewed commit: ["Give messaging clear exact
subtree
seman..."](https://github.com/alishahryar1/free-claude-code/commit/0a3baecf9470da4bb866c864c1d1f01abd517085)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=43593126)</sub>

> Greptile also left **1 inline comment** on this PR.

<!-- /greptile_comment -->
2026-07-11 22:26:16 -07:00
Ali Khokhar e37b504636 Preserve user messages during messaging clear (#1068)
## Problem

Messaging `/clear` used one untyped collection for both internal reply
references and platform deletion targets. Clearing a branch or
cancelling a voice task could therefore delete the customer's prompt or
voice note along with FCC's own status and reply messages.

## Changes

| Before | After |
| --- | --- |
| Tree transitions exposed one message-ID set for repository unindexing
and platform deletion. | Tree transitions now separate internal
`reference_ids` from FCC-owned `clearable_message_ids`. |
| Reply and global clear deleted user prompts and voice notes with FCC
output. | Clear removes FCC statuses, replies, notices, and the explicit
`/clear` command while preserving user-authored messages. |
| The persisted message log accepted ordinary inbound content. | The
clearable-message log accepts only FCC output and explicit clear
commands, and drops legacy user-content entries when loading. |
| Tests treated user-message deletion as successful cleanup. |
Deterministic and live messaging coverage enforce preservation across
branch, global, and voice clear paths. |

<!-- greptile_comment -->

<details open><summary><h3>Greptile Summary</h3></summary>

This PR narrows messaging clear behavior so user-authored messages are
preserved. The main changes are:

- Clearable platform IDs are separated from internal tree reference IDs.
- The session message log now tracks FCC-owned output and explicit clear
commands.
- Branch, global, and voice clear paths now avoid deleting user prompts
and voice notes.
- Tests, smoke coverage, docs, and the package version were updated.
</details>

<h3>Confidence Score: 5/5</h3>

This looks safe to merge after a small migration cleanup.

The clear paths now preserve user-authored messages, and current
clearable-log writers use the new shape consistently.

src/free_claude_code/messaging/session/clearable_message_log.py needs a
migration cleanup for old retained clear-command IDs during session
reload.

<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**
- Validated the messaging-clear-preservation contract by reviewing the
foreground pytest run log, which captured the exact command, working
directory, full test output, and exit code, and by examining the
artifact note and its capture log that summarize the command, test
count, exit code, and scope.

<a
href="https://app.greptile.com/trex/runs/14123111/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/messaging/session/clearable_message_log.py |
Replaces the broad message log with a clearable-message log, but the
migration filter can drop old retained clear-command IDs. |
| src/free_claude_code/messaging/session/store.py | Renames the
session-store API around clearable message IDs while keeping the same
persisted `message_log` key. |
| src/free_claude_code/messaging/trees/runtime.py | Returns internal
reference IDs separately from FCC-owned deletion IDs during branch
removal and chat-wide enumeration. |
| src/free_claude_code/messaging/trees/manager.py | Uses reference IDs
for repository cleanup and returns clearable IDs for platform deletion.
|
| src/free_claude_code/messaging/turn_intake.py | Stops recording
ordinary inbound content and records clear commands only when needed for
cleanup. |
| src/free_claude_code/messaging/commands.py | Deletes clearable IDs
plus the invoking clear command instead of deleting all branch reference
IDs. |
| src/free_claude_code/messaging/workflow.py | Aggregates clearable IDs
from tree state, the session log, and voice cancellation results. |
| src/free_claude_code/messaging/voice.py | Changes voice cancellation
deletion ownership so only FCC-authored status messages are clearable. |

</details>

<details open><summary><h3>Flowchart</h3></summary>

<a href="#gh-light-mode-only">

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Incoming message] --> B{Clear command?}
  B -- No --> C[Handle normal turn]
  C --> D[Record FCC outbound status]
  B -- Reply clear --> E[Record clear command]
  E --> F[Clear branch or voice task]
  F --> G[Delete FCC-owned IDs plus clear command]
  B -- Global clear --> H[Collect clearable IDs]
  H --> I[Reset conversation state]
  I --> J[Delete FCC-owned IDs plus clear command]
  D --> K[Clearable-message log]
  K --> H
```

</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"}}}%%
flowchart TD
  A[Incoming message] --> B{Clear command?}
  B -- No --> C[Handle normal turn]
  C --> D[Record FCC outbound status]
  B -- Reply clear --> E[Record clear command]
  E --> F[Clear branch or voice task]
  F --> G[Delete FCC-owned IDs plus clear command]
  B -- Global clear --> H[Collect clearable IDs]
  H --> I[Reset conversation state]
  I --> J[Delete FCC-owned IDs plus clear command]
  D --> K[Clearable-message log]
  K --> H
```

</a>
</details>

<a
href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22alishahryar1%2Ffree-claude-code%22%20on%20the%20existing%20branch%20%22ali%2Fpreserve-user-messages-on-clear%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22ali%2Fpreserve-user-messages-on-clear%22.%0A%0AFix%20the%20following%201%20code%20review%20issue.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%201%0Asrc%2Ffree_claude_code%2Fmessaging%2Fsession%2Fclearable_message_log.py%3A36-37%0A**Legacy%20Clear%20Commands%20Are%20Dropped**%0A%0AWhen%20an%20existing%20session%20file%20contains%20a%20previously%20retained%20clear%20command%20from%20the%20old%20log%2C%20it%20is%20stored%20as%20%60direction%3D%22in%22%60%20and%20%60kind%3D%22command%22%60.%20This%20new%20load%20filter%20drops%20that%20entry%20because%20it%20only%20keeps%20%60kind%3D%22clear_command%22%60%2C%20so%20a%20failed%20or%20cancelled%20%60%2Fclear%60%20command%20recorded%20before%20the%20upgrade%20is%20no%20longer%20retried%20by%20the%20next%20clear%20and%20remains%20on%20the%20platform.%0A%0A&repo=alishahryar1%2Ffree-claude-code&pr=1068&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodexDark.svg?v=6"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"><img
alt="Fix All in Codex"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"></picture></a>

<sub>Reviews (1): Last reviewed commit: ["Preserve user messages during
clear"](https://github.com/alishahryar1/free-claude-code/commit/af7a910facaa29a5ca8f7fb95ec2faae28798e62)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=43576921)</sub>

> Greptile also left **1 inline comment** on this PR.

**Context used:**

- Context used - CLAUDE.md
([source](https://app.greptile.com/alishahryar1/github/Alishahryar1/free-claude-code/-/custom-context?memory=d2fd24d8-0dec-4faf-8ee4-e085e215a2f8))

<!-- /greptile_comment -->
2026-07-11 18:25:20 -07:00
Ali Khokhar 3a7e0ccf7a Remove the native Anthropic provider transport (#1067)
## Problem

Ollama and llama.cpp still used a parallel native Anthropic transport
after the other providers moved to OpenAI Chat. That kept duplicate
request, SSE, recovery, model-list, and server-tool policy machinery
alive.

## Changes

| Before | After |
| --- | --- |
| Ollama and llama.cpp streamed through provider-specific Anthropic
`/messages` adapters. | Ollama and llama.cpp use the shared OpenAI Chat
transport. |
| Native request serialization, SSE normalization, error mapping, and
recovery remained beside the OpenAI path. | Native-only machinery is
removed and all providers share one transport lifecycle. |
| Routed models carried a capability object solely to permit native
server-tool passthrough. | Routing carries only route decisions; FCC
handles forced server tools locally and rejects lossy passthrough. |
| Ollama discovery used a separate `/api/tags` parser and rejected `/v1`
configuration. | Ollama discovery uses `/v1/models` and accepts either
root or `/v1` base URLs. |
| Obsolete native tests and a compatibility facade kept deleted
internals represented. | Tests cover the shared transport and real
Ollama product path without compatibility shims. |

<!-- greptile_comment -->

<details open><summary><h3>Greptile Summary</h3></summary>

This PR removes the native Anthropic transport path for local providers.
The main changes are:

- Ollama and llama.cpp now use the shared OpenAI Chat transport.
- Local provider base URLs are normalized to the OpenAI-compatible `/v1`
API root.
- Ollama discovery now uses the OpenAI-compatible model-listing path.
- Native Anthropic transport code and server-tool passthrough capability
metadata were removed.
- Tests and smoke coverage were updated for the shared transport path.
</details>


<h3>Confidence Score: 5/5</h3>

This looks safe to merge.

No blocking issues found in the changed code.

None.

<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**
- Ran the targeted local provider pytest slice and observed exit code 0.
- Executed the generated runtime harness to emulate the provider HTTP
interactions and capture a request trace.
- Validated the request trace showed two GET /v1/models calls authorized
as Bearer ollama for root and /v1 base URL configurations, and a POST
/v1/chat/completions authorized as Bearer llamacpp with streaming OpenAI
chat JSON payload.
- Confirmed the exact generated harness script used for the runtime
proof is the harness file referenced in the artifacts.

<a
href="https://app.greptile.com/trex/runs/14121848/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/providers/transports/openai_chat/base_url.py |
Adds a helper that normalizes local OpenAI-compatible server roots to
`/v1`. |
| src/free_claude_code/providers/llamacpp/client.py | Moves llama.cpp to
the shared OpenAI Chat transport with local base URL normalization. |
| src/free_claude_code/providers/ollama/client.py | Moves Ollama to the
shared OpenAI Chat transport with local base URL normalization. |
| src/free_claude_code/api/handlers/messages.py | Applies server-tool
rejection through the shared request policy instead of provider
passthrough metadata. |
| src/free_claude_code/application/routing.py | Removes provider
capability metadata from routed model results. |

</details>


<!-- greptile_failed_comments -->
<h3>Comments Outside Diff (1)</h3>

1. `src/free_claude_code/api/handlers/messages.py`, line 261-267
([link](https://github.com/alishahryar1/free-claude-code/blob/3c7ff176da46560c4d27b3846dca1ab1c7db561c/src/free_claude_code/api/handlers/messages.py#L261-L267))

<a href="#"><img alt="P2"
src="https://greptile-static-assets.s3.amazonaws.com/badges/p2.svg?v=9"
align="top"></a> **Native Server Tools Always Reject**

With the passthrough capability check removed, Ollama and llama.cpp
requests that previously used their native Anthropic transport for
`web_search` or `web_fetch` are rejected before provider execution. The
default `ENABLE_WEB_SERVER_TOOLS=false` now makes forced server-tool
requests return an invalid-request error instead of reaching the local
provider path that used to support them.

<a
href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22alishahryar1%2Ffree-claude-code%22%20on%20the%20existing%20branch%20%22ali%2Fremove-native-anthropic-transport%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22ali%2Fremove-native-anthropic-transport%22.%0A%0AThis%20is%20a%20comment%20left%20during%20a%20code%20review.%0APath%3A%20src%2Ffree_claude_code%2Fapi%2Fhandlers%2Fmessages.py%0ALine%3A%20261-267%0A%0AComment%3A%0A**Native%20Server%20Tools%20Always%20Reject**%0A%0AWith%20the%20passthrough%20capability%20check%20removed%2C%20Ollama%20and%20llama.cpp%20requests%20that%20previously%20used%20their%20native%20Anthropic%20transport%20for%20%60web_search%60%20or%20%60web_fetch%60%20are%20rejected%20before%20provider%20execution.%20The%20default%20%60ENABLE_WEB_SERVER_TOOLS%3Dfalse%60%20now%20makes%20forced%20server-tool%20requests%20return%20an%20invalid-request%20error%20instead%20of%20reaching%20the%20local%20provider%20path%20that%20used%20to%20support%20them.%0A%0AHow%20can%20I%20resolve%20this%3F%20If%20you%20propose%20a%20fix%2C%20please%20make%20it%20concise.&repo=alishahryar1%2Ffree-claude-code&pr=1067&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodexDark.svg?v=6"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodex.svg?v=6"><img
alt="Fix in Codex"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodex.svg?v=6"></picture></a>
<!-- /greptile_failed_comments -->

<sub>Reviews (2): Last reviewed commit: ["Normalize local OpenAI v1 base
URLs"](https://github.com/alishahryar1/free-claude-code/commit/2355eac247a6e411f89a781f46e784636ced98d6)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=43572841)</sub>

<!-- /greptile_comment -->
2026-07-11 17:53:42 -07:00
Ali Khokhar ef76bddd58 Make Telegram startup notices clearable (#1066)
## Problem

Telegram's online notice was sent directly by the SDK runtime and its
message ID was discarded, so `/clear` could not delete it. Moving
delivery into the workflow also needs to keep slow sends from blocking
commands and prevent acknowledged notices from losing clear ownership.

## Changes

| Before | After |
| --- | --- |
| The Telegram runtime sent a transport-specific startup side effect. |
The platform declares a semantic notice intent that the application
gives to the workflow after transport readiness. |
| Startup delivery bypassed the persisted message log. | The workflow
renders and records each acknowledged notice in the same bounded log
used by `/clear`. |
| Serializing send and record held workflow state across platform I/O. |
A dedicated clear generation reserves publication, delivery runs outside
the state lock, and a short receipt finalizer commits or compensates. |
| Concurrent clear, cancellation, or record failure could leave a
delivered notice unowned. | Clear or cancellation deletes a late
receipt; record failure deletes it; failed deletion restores tracking
for a later `/clear`. |
| A standalone `/clear` command could evict an older target at the log
cap. | Successful standalone clear owns its command ID directly, while
failed or cancelled clear records it for the next attempt. |
| Startup ownership races were implicit. | Deterministic race, failure,
cap, restart, and product-smoke coverage enforce the final state machine
in version 3.5.10. |

<!-- greptile_comment -->

<details open><summary><h3>Greptile Summary</h3></summary>

This PR makes Telegram startup notices clearable through the messaging
workflow. The main changes are:

- Moves the Telegram online notice out of the SDK runtime and into
workflow-owned publication.
- Adds a startup-notice intent to platform composition and publishes it
after runtime start and restored-status repair.
- Records delivered startup notice IDs for later `/clear` ownership,
with delete compensation on interrupted ownership transfer.
- Defers standalone `/clear` command ID recording so it cannot evict
older deletion targets at the log cap.
- Adds tests and smoke coverage for startup notice clearing,
cancellation, failures, cap pressure, persistence, and startup ordering.
- Bumps the package version and lockfile to 3.5.10.
</details>

<h3>Confidence Score: 5/5</h3>

This looks safe to merge.

No blocking issues were found in the changed code.

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**
- A focused proof run for the telegram startup tests completed, showing
121 tests passed in 2.94 seconds with EXIT\_CODE 0.
- A smoke proof run for the same flow completed, showing 18 tests
skipped in 0.97 seconds with EXIT\_CODE 0.
- The shell wrapper issue was addressed by re-running with bash -lc,
producing a clean result with EXIT\_CODE 0 in the final artifact.

<a
href="https://app.greptile.com/trex/runs/14118230/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/messaging/workflow.py | Adds workflow-owned
startup notice sending, tracking, compensation, and clear-generation
ordering. |
| src/free_claude_code/messaging/turn_intake.py | Defers standalone
`/clear` command ID recording until failure or cancellation paths need
it. |
| src/free_claude_code/runtime/application.py | Publishes optional
startup notices after messaging runtime start and restored-status
repair. |
| src/free_claude_code/messaging/platforms/factory.py | Creates a
Telegram startup-notice intent when an allowed Telegram user is
configured. |
| src/free_claude_code/messaging/platforms/telegram.py | Removes the
direct Telegram runtime startup-message side effect. |

</details>

<sub>Reviews (2): Last reviewed commit: ["Make Telegram startup notices
clearable"](https://github.com/alishahryar1/free-claude-code/commit/6e779006e0cdaf1df24c27a8d04784e2d7220a66)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=43565904)</sub>

<!-- /greptile_comment -->
2026-07-11 16:27:58 -07:00
Ali Khokhar eda8ea3060 Use task status as the sole stop confirmation (#1065)
## Problem

Messaging `/stop` edited each affected task status to `Stopped` and also
posted a second success message. The duplicate confirmation added noise
even though the existing status already represented the terminal result.

## Changes

| Before | After |
| --- | --- |
| Successful active, queued, global, and bound-voice stops posted a
second confirmation. | Successful stops use the affected task status as
their sole success UI. |
| Stop commands returned an ambiguous integer or `None`. | A typed
`StopOutcome` carries the cancelled count and terminal status ownership.
|
| Statusless voice cancellation could become silent if confirmations
were removed unconditionally. | Statusless voice cancellation receives
one fallback confirmation. |
| A global stop could under-report work when any affected status was in
another chat. | The invoking chat receives one summary whenever any
affected status is outside its scope. |
| Zero-work global stops reported that zero requests were cancelled. |
No-op global and reply stops report that there was nothing to stop. |
| Runtime and product coverage encoded the duplicate message. | Runtime
mapping and Discord/Telegram product smokes cover active, queued, voice,
no-op, and fallback behavior. |
| The package version was 3.5.8. | The package version is 3.5.9 with an
updated lockfile. |

<!-- greptile_comment -->

<details open><summary><h3>Greptile Summary</h3></summary>

This PR changes `/stop` so task statuses become the main success
feedback. The main changes are:

- Added a typed stop outcome for cancelled counts and status feedback
ownership.
- Suppressed duplicate stop confirmations when the invoking chat already
has complete status feedback.
- Kept explicit fallback messages for no-op stops, statusless voice
cancellations, and cross-chat stop results.
- Updated runtime mapping, docs, product smokes, tests, and the package
version.
</details>

<h3>Confidence Score: 5/5</h3>

This looks safe to merge.

No blocking issues found in the changed code.

None.

<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**
- Ran the live messaging product smoke test with FCC\_LIVE\_SMOKE=1 and
FCC\_SMOKE\_TARGETS=messaging, executing the command uv run pytest under
/home/user/repo; the run exited with code 0 and 17 tests passed in
1.34s.
- Reviewed the test run log to verify proper shutdown behavior, noting
Discord and Telegram stop statuses, a queued trace, and cancellation
messages indicating shutdown tasks were being canceled.
- Linked the stop-product-smoke-20260711.log artifact for review of the
run's stop behavior.

<a
href="https://app.greptile.com/trex/runs/14115543/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/messaging/command_context.py | Adds `StopOutcome`
and updates stop command context signatures. |
| src/free_claude_code/messaging/commands.py | Routes stop confirmations
through the new outcome and fallback rules. |
| src/free_claude_code/messaging/workflow.py | Builds stop outcomes from
voice cancellations and tree cancellation effects. |
| src/free_claude_code/runtime/application.py | Maps the messaging stop
outcome back to the runtime stop result count. |
| tests/messaging/test_handler.py | Covers same-chat status feedback,
cross-chat fallback, no-op stops, and voice fallback behavior. |
| smoke/product/test_messaging_product_live.py | Updates product smokes
for status-only stop success feedback. |

</details>

<sub>Reviews (2): Last reviewed commit: ["Use task status as the sole
stop
confirm..."](https://github.com/alishahryar1/free-claude-code/commit/98f0acb01b3405c2afd918539eff49b9410bf487)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=43560341)</sub>

<!-- /greptile_comment -->
2026-07-11 15:23:26 -07:00
Ali Khokhar df038c2470 Retry degraded NVIDIA NIM functions as overloads (#1064)
## Problem

NVIDIA NVCF can return HTTP 400 when a deployed function is DEGRADED,
even though the failure is transient. FCC treated that response as a
deterministic invalid request and never used its provider-owned retry
budget. Fixes #1057.

## Changes

| Before | After |
| --- | --- |
| Every NVIDIA HTTP 400 was non-retryable. | The NVIDIA adapter
recognizes only the structured NVCF `Function id …: DEGRADED function
cannot be invoked` response. |
| A degraded function failed after one attempt. | The shared limiter
applies its existing five-attempt exponential backoff without mutating
the request or adding another retry loop. |
| Exhaustion returned `INVALID_REQUEST / 400`. | Exhaustion returns
canonical `OVERLOADED / 529` while preserving the redacted upstream HTTP
400 detail and request ID. |
| NVIDIA-specific wording could have leaked into shared classification.
| The exact marker stays NVIDIA-owned; shared provider policy owns
canonical semantics, diagnostics, and scheduling, while API wire mapping
remains unchanged. |
| The degraded-function boundary had no deterministic coverage. | Tests
cover recovery, exact exhaustion, near misses, provider isolation, raw
exception preservation, trace metadata, and credential redaction; all
five CI gates pass with 2,214 tests passed and 7 skipped. |
| Package version was 3.5.7. | Package version is 3.5.8 with an updated
lockfile. |

<!-- greptile_comment -->

<details open><summary><h3>Greptile Summary</h3></summary>

This PR teaches NVIDIA NIM degraded-function failures to use the shared
overload retry path. The main changes are:

- Adds a provider-specific failure override hook.
- Maps the exact NVCF degraded-function HTTP 400 marker to canonical
overload semantics.
- Threads the override through shared retry and final failure
classification.
- Adds focused tests for retry, exhaustion, near misses, provider
isolation, redaction, and trace metadata.
- Updates docs, smoke coverage metadata, package version, and lockfile.
</details>


<h3>Confidence Score: 5/5</h3>

This looks safe to merge after considering the narrow NVIDIA error-body
match.

The retry and final classification flow preserve the raw upstream error,
and non-NVIDIA providers keep the existing 400 behavior.

src/free_claude_code/providers/nvidia_nim/client.py should harden the
degraded marker lookup for nested SDK error bodies.

<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**
- T-Rex produced a proof for the posted P1 finding and linked it to the
corresponding review comment.
- A contract-validation proof was captured showing the full command
transcript with timestamps, working directory, commands, pytest verbose
output, and exit codes.
- The focused Nvidia degraded retry test ran and completed with 8 passed
in 2.43s.
- A broader test run reported worker crashes, with 3 failed and 70
passed.
- A serial test for test\_openai\_compat\_5xx\_retry.py timed out after
a hang, exiting at 124.

<a
href="https://app.greptile.com/trex/runs/14112472/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/providers/nvidia_nim/client.py | Adds
NVIDIA-specific degraded-function detection; the match is narrow and
only reads a top-level `detail` field. |
| src/free_claude_code/providers/rate_limit.py | Uses provider overrides
for retry qualification while preserving the raw exception after retry
exhaustion. |
| src/free_claude_code/providers/failure_policy.py | Adds the shared
override type and final classification hook, plus a reusable
overloaded-provider failure constructor. |
| src/free_claude_code/providers/transports/openai_chat/transport.py |
Passes provider-specific failure overrides into stream creation retries
and final failure mapping. |
| tests/providers/test_nvidia_nim_degraded_retry.py | Adds coverage for
NVIDIA degraded-function retry success, retry exhaustion, non-matching
400s, provider isolation, redaction, and traces. |

</details>


<!-- greptile_failed_comments -->
<h3>Comments Outside Diff (1)</h3>

1. General comment 

<a href="#"><img alt="P1"
src="https://greptile-static-assets.s3.amazonaws.com/badges/p1.svg?v=9"
align="top"></a> **Adjacent OpenAI-compatible 5xx exhaustion test
crashes workers and hangs serially**

   - **Bug**
- The requested adjacent retry/rate-limit coverage is not stable on
current head. Under xdist, three parameters of
`test_nim_stream_openai_5xx_exhausted_emits_user_message` caused workers
to terminate unexpectedly, producing an exit code 1. A follow-up serial
rerun passed the 500 parameter but timed out after 60 seconds while
running the 502 parameter, indicating the exhausted 5xx path can hang or
terminate the worker rather than completing deterministically.
   - **Cause**
- The executed evidence points to the OpenAI-compatible NIM 5xx
exhaustion path exercised by
`tests/providers/test_openai_compat_5xx_retry.py::test_nim_stream_openai_5xx_exhausted_emits_user_message`.
The exact root cause was not isolated within the validation budget, but
the affected area overlaps changed retry/transport handling files.
   - **Fix**
- Investigate the OpenAI-compatible streaming 5xx exhaustion path for
non-terminating retry/stream cleanup or worker-fatal behavior. Ensure
exhausted 5xx cases raise the expected user-facing error promptly for
all status parameters, then rerun the adjacent command and the targeted
serial parametrized test.

<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>

<!-- /greptile_failed_comments -->

<a
href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22alishahryar1%2Ffree-claude-code%22%20on%20the%20existing%20branch%20%22ali%2Fretry-nim-degraded-function%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22ali%2Fretry-nim-degraded-function%22.%0A%0AFix%20the%20following%201%20code%20review%20issue.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%201%0Asrc%2Ffree_claude_code%2Fproviders%2Fnvidia_nim%2Fclient.py%3A126-127%0A**Nested%20Error%20Body%20Misses%20Retry**%0A%0AWhen%20the%20OpenAI%20SDK%20exposes%20a%20400%20response%20as%20the%20common%20nested%20error%20shape%2C%20such%20as%20%60%7B%22error%22%3A%20%7B%22message%22%3A%20%22Function%20id%20...%3A%20DEGRADED%20function%20cannot%20be%20invoked%22%7D%7D%60%2C%20this%20lookup%20never%20sees%20the%20degraded%20marker.%20That%20path%20falls%20back%20to%20the%20shared%20400%20handling%2C%20so%20a%20transient%20degraded%20NVCF%20function%20still%20fails%20after%20one%20attempt%20instead%20of%20using%20the%20provider%20retry%20budget.%0A%0A&repo=alishahryar1%2Ffree-claude-code&pr=1064&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodexDark.svg?v=6"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"><img
alt="Fix All in Codex"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"></picture></a>

<sub>Reviews (1): Last reviewed commit: ["Retry degraded NVIDIA NIM
functions as
o..."](https://github.com/alishahryar1/free-claude-code/commit/2cc7f056a73d1baefb1e1395b181d26efc32dc9e)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=43555691)</sub>

> Greptile also left **1 inline comment** on this PR.

<!-- /greptile_comment -->
2026-07-11 14:28:41 -07:00
Ali Khokhar 26cc73e6ce Use installed metadata as the single package version source (#1051)
## Problem

FCC runtime surfaces reported stale, unrelated versions, and users could
not inspect the installed FCC version without starting the server or
scaffolding configuration.

## Changes

| Before | After |
| --- | --- |
| FastAPI/OpenAPI and the web-tools user agent duplicated stale release
literals. | Every FCC runtime surface reads installed distribution
metadata through one `core.version` owner. |
| FCC-owned commands had no side-effect-free version query. |
`fcc-server`, `free-claude-code`, and `fcc-init` print the installed
version whenever `--version` is present, before any configuration or
process work. |
| Wrapped Claude and Codex argument handling was adjacent to FCC command
behavior. | Claude and Codex launchers remain transparent and pass
`--version` to their wrapped clients unchanged. |
| A source-only checkout had no explicit fallback contract. | Missing
distribution metadata reports `0+unknown`, while malformed installed
metadata still fails visibly. |
| Version behavior lacked end-to-end contract coverage. | API, CLI,
metadata, user-agent, feature-inventory, and live command tests verify
one value and zero CLI side effects; the complete 2,077-test CI gate
passes. |

<!-- greptile_comment -->

<details open><summary><h3>Greptile Summary</h3></summary>

This PR makes installed package metadata the single source for the FCC
version. The main changes are:

- Adds `core.version.package_version()` with a source-checkout fallback.
- Uses that version in FastAPI/OpenAPI metadata and web-tool User-Agent
headers.
- Adds side-effect-free `--version` handling for FCC-owned CLI
entrypoints.
- Keeps Claude and Codex launchers transparent to wrapped client
arguments.
- Updates tests, smoke coverage, docs, and package metadata to `3.5.0`.
</details>

<h3>Confidence Score: 5/5</h3>

This looks safe to merge.

No blocking issues found in the changed code.

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 version contract pytest run completed successfully with
EXIT\_CODE: 0, as captured in the version contract pytest log.
- The direct CLI version commands sequence completed with final
EXIT\_CODE: 0, as recorded in the CLI version commands log.

<a
href="https://app.greptile.com/trex/runs/14086115/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/core/version.py | Adds the canonical
installed-metadata version helper with an explicit missing-metadata
fallback. |
| src/free_claude_code/cli/entrypoints.py | Adds early `--version`
output for FCC-owned server and init commands before startup or config
work. |
| src/free_claude_code/api/app.py | Uses the centralized package version
for FastAPI and OpenAPI metadata. |
| src/free_claude_code/api/web_tools/constants.py | Uses the centralized
package version in the outbound web-tool User-Agent. |

</details>

<sub>Reviews (2): Last reviewed commit: ["Use installed metadata as the
package
ve..."](https://github.com/alishahryar1/free-claude-code/commit/f240f9c363115e63f407d7ac8d5c35833f6b66c8)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=43500448)</sub>

<!-- /greptile_comment -->
2026-07-11 03:45:06 -07:00
Ali Khokhar 2bcaf3ac74 Make messaging trees atomic ownership boundaries (#1048)
## Problem

Messaging tree state, queue coordination, task ownership, and
persistence were jointly mutated across several classes. Raw message IDs
were treated as globally unique, allowing cross-chat collisions and
unsafe cancellation or clear ordering.

## Changes

| Before | After |
| --- | --- |
| Managers and processors coordinated partial tree mutations through
exposed locks and mutable nodes. | MessageTree owns atomic transitions
and returns detached effects to task, UI, and persistence owners. |
| Raw message IDs and task identities could collide across chats or
detached generations. | Scoped tree identities and opaque claim IDs
isolate chats and reject stale task writes. |
| Session snapshots duplicated graph links and retained ingress
payloads. | Lean scoped snapshots rebuild validated indexes and continue
reading existing session files. |
| Stop, clear, and runner persistence could interleave across commit
boundaries. | Admission epochs, cancellation-safe detach, and
authoritative writes make committed cleanup durable. |
| Tree implementation classes leaked through messaging package exports.
| Adapter-facing values and ports remain supported while tree internals
stay internal. |

<!-- greptile_comment -->

<details open><summary><h3>Greptile Summary</h3></summary>

This PR makes messaging trees own their state transitions and scoped
identities. The main changes are:

- Scoped tree and voice ownership by platform and chat.
- Opaque claim IDs for queued task execution.
- Manager-owned atomic cancellation, clear, and successor task launch
paths.
- Lean scoped snapshots with legacy session restore support.
- Messaging tree internals removed from the public package surface.
</details>


<h3>Confidence Score: 5/5</h3>

This looks safe to merge.

No blocking issues found in the changed code.

<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**
- Executed the messaging and contract-boundary test suite with pytest
across all specified test modules.
- Observed the run completed with 96 tests passing in 4.10 seconds and
an exit code of 0.
- The exact pytest command used for the run is documented in the proof
to enable reproducibility of the test scope.
- The run log is available as an artifact for reviewers to inspect test
output and details.

<a
href="https://app.greptile.com/trex/runs/14083891/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/messaging/trees/runtime.py | Adds claim-scoped
state transitions and cancellation tombstones for late runner writes. |
| src/free_claude_code/messaging/trees/manager.py | Centralizes
aggregate publication, branch removal, global clear, and successor task
launch decisions. |
| src/free_claude_code/messaging/trees/processor.py | Runs tasks by
opaque claim ID and routes cleanup through manager-owned finish
handling. |
| src/free_claude_code/messaging/trees/snapshot.py | Serializes scoped
tree snapshots and restores supported legacy tree shapes. |
| src/free_claude_code/messaging/voice.py | Scopes pending voice
registrations by message scope and message ID. |

</details>


<!-- greptile_failed_comments -->
<h3>Comments Outside Diff (1)</h3>

1. `src/free_claude_code/messaging/commands.py`, line 161-164
([link](https://github.com/alishahryar1/free-claude-code/blob/a4e49f082a9d3ffc1f6cdf3ab6a065b0f22a759d/src/free_claude_code/messaging/commands.py#L161-L164))

<a href="#"><img alt="P1"
src="https://greptile-static-assets.s3.amazonaws.com/badges/p1.svg?v=9"
align="top"></a> **Voice Cancellation Is Unscoped**

The tree reply path is now scoped by `incoming.scope`, but the voice
fallback still cancels by only `chat_id` and `reply_id`. If Discord and
Telegram both have the same raw chat/message IDs, a reply `/clear` from
one platform can cancel a pending voice note from the other platform,
crossing the ownership boundary this PR adds for message trees.

   <details><summary><strong>Artifacts</strong></summary><br />

**[Repro: focused pytest harness that models cross-platform raw ID
collision for voice
cancellation](https://app.greptile.com/trex/artifacts/0ad480a9-4e20-4b4e-970e-63aebc4577b3)**

- Contains supporting evidence from the run (text/x-python;
charset=utf-8).

**[Repro: verbose pytest output showing unscoped cancel\_pending\_voice
call and Discord-owned voice cancellation from Telegram
/clear](https://app.greptile.com/trex/artifacts/ead824f3-2f41-4028-a8e3-8359c5f6d3a9)**

- Keeps the command output available without making the summary
code-heavy.

<a
href="https://app.greptile.com/trex/runs/14082218/artifacts?artifact=0ad480a9-4e20-4b4e-970e-63aebc4577b3"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewArtifactsDark.svg?v=4"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewArtifacts.svg?v=4"><img
alt="View artifacts"
src="https://greptile-static-assets.s3.amazonaws.com/badges/ViewArtifacts.svg?v=4"></picture></a>
   </details>

<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>

<a
href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22alishahryar1%2Ffree-claude-code%22%20on%20the%20existing%20branch%20%22architecture%2Fmessage-tree-ownership%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22architecture%2Fmessage-tree-ownership%22.%0A%0AThis%20is%20a%20comment%20left%20during%20a%20code%20review.%0APath%3A%20src%2Ffree_claude_code%2Fmessaging%2Fcommands.py%0ALine%3A%20161-164%0A%0AComment%3A%0A**Voice%20Cancellation%20Is%20Unscoped**%0A%0AThe%20tree%20reply%20path%20is%20now%20scoped%20by%20%60incoming.scope%60%2C%20but%20the%20voice%20fallback%20still%20cancels%20by%20only%20%60chat_id%60%20and%20%60reply_id%60.%20If%20Discord%20and%20Telegram%20both%20have%20the%20same%20raw%20chat%2Fmessage%20IDs%2C%20a%20reply%20%60%2Fclear%60%20from%20one%20platform%20can%20cancel%20a%20pending%20voice%20note%20from%20the%20other%20platform%2C%20crossing%20the%20ownership%20boundary%20this%20PR%20adds%20for%20message%20trees.%0A%0AHow%20can%20I%20resolve%20this%3F%20If%20you%20propose%20a%20fix%2C%20please%20make%20it%20concise.&repo=alishahryar1%2Ffree-claude-code&pr=1048&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodexDark.svg?v=6"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodex.svg?v=6"><img
alt="Fix in Codex"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixInCodex.svg?v=6"></picture></a>
<!-- /greptile_failed_comments -->

<sub>Reviews (4): Last reviewed commit: ["Serialize successor task
publication
wit..."](https://github.com/alishahryar1/free-claude-code/commit/ec8744a8882c1ebc38d5dc7e87aaf2e31b08f653)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=43492190)</sub>

<!-- /greptile_comment -->
2026-07-11 02:51:23 -07:00
Ali Khokhar 701a394697 Make provider capabilities semantic and typed (#1047)
## Problem

Provider metadata mixed descriptive strings and transport-family names
with product policy. The Messages API had to know provider
implementation details to decide server-tool behavior, while locality
and thinking metadata had ambiguous owners.

## Changes

| Before | After |
| --- | --- |
| Provider descriptors exposed transport names and untyped capability
strings. | Provider descriptors expose an immutable semantic value
containing only locality and server-tool passthrough. |
| The Messages handler derived provider sets from transport families. |
`ResolvedModel` carries catalog capabilities and the handler asks the
resolved semantic policy. |
| Discovery, Admin, and smoke selection inferred locality from
credentials or string membership. | Discovery, Admin, and smoke
selection read the catalog-owned `local` capability. |
| Provider-wide thinking strings competed with discovered model
metadata. | `ProviderModelInfo.supports_thinking` remains the sole
per-model thinking authority. |
| Invalid mapped providers could become raw catalog lookup failures
during the migration. | Routing and provider construction share the
canonical typed unknown-provider error. |
| LM Studio smoke contracts described a native Anthropic transport. | LM
Studio smoke contracts describe its OpenAI-chat-backed Messages path. |
| Tests encoded transport identities as product behavior. | Tests prove
both directions of capability-versus-identity independence while
preserving existing wire behavior and diagnostics. |

<!-- greptile_comment -->

<details open><summary><h3>Greptile Summary</h3></summary>

This PR moves provider policy from transport names to typed catalog
capabilities. The main changes are:

- Added immutable provider capability values for locality and
server-tool passthrough.
- Routed provider capabilities through `ResolvedModel` for Messages API
policy.
- Updated admin status, discovery, smoke config, docs, and tests to read
semantic capabilities.
- Centralized unknown-provider diagnostics for routing and provider
construction.
- Bumped the package version and lockfile to `3.4.22`.
</details>

<h3>Confidence Score: 5/5</h3>

This looks safe to merge.

No blocking issues found in the changed code.

None.

<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 Pytest run for the provider capabilities changes was executed and
completed successfully, as shown by the log's EXIT\_CODE: 0.
- The Ruff linter run for the provider capabilities changes was executed
and completed successfully, as shown by the log's EXIT\_CODE: 0.
- The focused suite exercised the changed code paths via repository
tests rather than relying solely on static inspection.

<a
href="https://app.greptile.com/trex/runs/14074560/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/config/provider_catalog.py | Replaces transport
and string capability metadata with typed immutable provider
capabilities. |
| src/free_claude_code/application/routing.py | Adds catalog
capabilities to resolved models and uses the shared unknown-provider
error. |
| src/free_claude_code/api/handlers/messages.py | Uses resolved semantic
capabilities to decide server-tool passthrough. |
| src/free_claude_code/config/admin/status.py | Classifies local
providers through the new catalog capability. |
| src/free_claude_code/providers/runtime/discovery.py | Uses typed
locality to decide which providers are discovered only when referenced.
|
| src/free_claude_code/application/errors.py | Adds a shared constructor
for canonical unknown-provider messages. |

</details>

<sub>Reviews (1): Last reviewed commit: ["Make provider capabilities
semantic and
..."](https://github.com/alishahryar1/free-claude-code/commit/b2732ef74d61c632ccae332a19aaa655f45a96e7)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=43475337)</sub>

<!-- /greptile_comment -->
2026-07-10 22:48:47 -07:00
Ali Khokhar e22a38b2c2 Canonicalize provider failure and retry ownership (#1046)
## Problem

Provider SDK classification, retry policy, canonical failures, and
downstream wire errors shared exception types across layers. That
blurred ownership and let cleanup or provisional Responses tool failures
mask the real provider diagnostic.

## Changes

| Before | After |
| --- | --- |
| Provider failures carried Anthropic wire types and core code
classified OpenAI/httpx errors. | Protocol-neutral `ExecutionFailure`
values cross layers, providers classify SDK errors, and protocol
packages map wire types. |
| Provider adapters could author terminal wire events. | The HTTP commit
boundary selects non-2xx JSON or a protocol terminal event with one
ingress request ID. |
| Retry policy and diagnostic handling were spread across core and
provider modules. | Providers own the unchanged retry budgets while
neutral core utilities own bounded credential redaction. |
| Stream cleanup could replace an already-mapped provider failure. |
Cleanup records safe metadata and preserves the canonical failure,
status, and diagnostic. |
| An incomplete Responses tool could preempt a later provider failure. |
Tool-finalization errors remain provisional so canonical provider
failures take precedence. |
| Readiness failures reused provider exception types. |
Application-owned errors represent deterministic validation and
availability phases without terminal retry headers. |
| Legacy exception and recovery owners remained importable. | Obsolete
modules are deleted without shims, architecture rules enforce the
boundaries, and package version is 3.4.21. |

<!-- greptile_comment -->

<details open><summary><h3>Greptile Summary</h3></summary>

This PR canonicalizes provider failure handling across the API boundary.
The main changes are:

- Adds protocol-neutral execution failure values and safe diagnostics.
- Moves SDK and HTTP failure classification into provider-owned policy.
- Lets Messages and Responses choose their own wire error payloads.
- Preserves canonical failures across stream cleanup and committed
stream failures.
- Makes incomplete Responses tool errors provisional until finalization.
</details>

<h3>Confidence Score: 5/5</h3>

This looks safe to merge.

No blocking issues found in the changed code.

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**
- Ran the API failure contract suite and related tests
(tests/api/test\_execution\_failure\_contract.py,
tests/core/test\_failure\_protocol\_mapping.py,
tests/providers/test\_execution\_failure\_boundary.py,
tests/providers/test\_failure\_policy.py); 48 passed in 3.36s.
- Ran the streaming boundaries tests including response streams, stream
recovery, and streaming errors; 70 passed in 5.36s.
- Ran the OpenAI responses tests; 20 passed in 4.42s.

<a
href="https://app.greptile.com/trex/runs/14071383/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/providers/transports/http.py | Adds cleanup-safe
stream closing that preserves established outcomes. |
| src/free_claude_code/core/openai_responses/stream.py | Preserves
canonical execution failures when committed Responses streams fail. |
| src/free_claude_code/core/openai_responses/streaming/assembler.py |
Keeps malformed tool-call errors provisional so later provider failures
can win. |
| src/free_claude_code/core/failures.py | Defines neutral failure kinds
and exception-group lookup for execution failures. |

</details>

<sub>Reviews (2): Last reviewed commit: ["Preserve canonical outcomes in
grouped
a..."](https://github.com/alishahryar1/free-claude-code/commit/f57f21241dbe582985627ed4fb40734b2c656809)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=43468297)</sub>

<!-- /greptile_comment -->
2026-07-10 21:33:50 -07:00
Ali Khokhar f8c21a48f2 Introduce a typed application boundary for provider execution (#1045)
## Problem

The HTTP adapter owned model routing, provider execution, and
runtime-facing contracts, so API handlers depended on provider
implementation types. Provider preflight also discovered private request
builders dynamically, obscuring the boundary that must fail before
streaming begins.

## Changes

| Before | After |
| --- | --- |
| `api/` owned model routing and shared provider execution. |
`application/` owns routing and a settings-independent
`ProviderExecutor`. |
| API handlers accepted `BaseProvider` callbacks. | API handlers consume
the narrow structural `ProviderPort`. |
| `BaseProvider` discovered `_build_request_body` dynamically. | Both
transport families implement explicit abstract preflight, with LM Studio
composing context validation. |
| Request leases, task control, and provider model metadata had
adapter/provider owners. | Application-owned ports and immutable values
define those cross-package contracts. |
| Boundary direction was implicit. | Architecture contracts and
documentation enforce the final dependency direction. |
| Package version was `3.4.19`. | Package version is `3.4.20`, with the
lockfile updated. |
| Coverage followed the old module layout. | Deterministic
boundary/preflight regressions and live Messages/Responses smokes cover
the new shape. |

<!-- greptile_comment -->

<details open><summary><h3>Greptile Summary</h3></summary>

This PR adds a typed application boundary for provider execution. The
main changes are:

- New `application` package for routing, execution, ports, and model
metadata.
- API handlers now call application-owned routing and provider
execution.
- Provider preflight is now explicit on the transport families.
- Runtime API composition now uses a task-control port for `/stop`.
- Import-boundary tests, smoke references, docs, version, and lockfile
were updated.
</details>

<h3>Confidence Score: 5/5</h3>

This looks safe to merge.

No blocking issues found in the changed code.

None.

<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**
- Ran a deterministic pytest run for the provider boundary preflight,
which completed with exit code 0 and 102 tests passing in 4.77 seconds.
- Launched the environment presence check as part of the preflight,
which completed with exit code 0 and confirmed
OPENCODE\_API\_KEY=\[REDACTED\] matched.
- Attempted the live provider smoke test, which completed with exit code
0 and 2 tests skipped due to incomplete smoke configuration.

<a
href="https://app.greptile.com/trex/runs/14067905/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/application/execution.py | Moves shared provider
execution into the application layer and keeps eager preflight before
token counting and streaming. |
| src/free_claude_code/application/ports.py | Adds structural provider,
request-runtime, and task-control protocols used across the new
boundary. |
| src/free_claude_code/api/routes.py | Updates route composition to use
the application provider resolver and task-control stop path. |
| src/free_claude_code/providers/base.py | Makes provider preflight
explicit by requiring subclasses or transport bases to implement it. |
| src/free_claude_code/providers/transports/openai_chat/transport.py |
Adds OpenAI-chat preflight through the same request-body builder used by
streaming. |
|
src/free_claude_code/providers/transports/anthropic_messages/transport.py
| Adds native Messages preflight through the native request-body
builder. |
| src/free_claude_code/providers/model_listing.py | Keeps provider
model-list parsing while moving `ProviderModelInfo` ownership to the
application layer. |
| src/free_claude_code/runtime/bootstrap.py | Passes the runtime object
through the new `tasks` service slot. |
| tests/contracts/test_import_boundaries.py | Extends import-boundary
tests for the new application package. |

</details>

<details open><summary><h3>Flowchart</h3></summary>

<a href="#gh-light-mode-only">

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart LR
  API[api handlers and routes] --> Routing[application.routing]
  API --> Executor[application.execution]
  API --> Ports[application.ports]
  Executor --> ProviderPort[ProviderPort]
  ProviderPort --> Preflight[preflight_stream]
  ProviderPort --> Stream[stream_response]
  Runtime[runtime bootstrap and provider manager] --> Ports
  Providers[providers] --> Metadata[application.model_metadata]
  Executor --> Core[core anthropic and trace]
  Routing --> Config[config settings and model refs]
```

</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"}}}%%
flowchart LR
  API[api handlers and routes] --> Routing[application.routing]
  API --> Executor[application.execution]
  API --> Ports[application.ports]
  Executor --> ProviderPort[ProviderPort]
  ProviderPort --> Preflight[preflight_stream]
  ProviderPort --> Stream[stream_response]
  Runtime[runtime bootstrap and provider manager] --> Ports
  Providers[providers] --> Metadata[application.model_metadata]
  Executor --> Core[core anthropic and trace]
  Routing --> Config[config settings and model refs]
```

</a>
</details>

<sub>Reviews (1): Last reviewed commit: ["Introduce typed application
boundary"](https://github.com/alishahryar1/free-claude-code/commit/4cdcf97231c812c6f568ca3d74af7ce759d7f2dc)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=43462788)</sub>

<!-- /greptile_comment -->
2026-07-10 20:06:57 -07:00
Ali Khokhar 4a0a0360de Move protocol models to their protocol owners (#1044)
## Problem

Anthropic Messages and OpenAI Responses wire models lived under the
inbound API adapter. Neutral protocol and provider code therefore
duck-typed requests, obscuring ownership and weakening dependency
boundaries.

## Changes

| Before | After |
| --- | --- |
| The API package owned Anthropic and Responses protocol models. | Each
protocol package owns and publicly exports its wire models. |
| Core and provider request paths accepted `Any` and probed known fields
with `getattr()`. | Core, transports, and providers consume concrete
`MessagesRequest` values. |
| Responses conversion and streaming received a dumped request mapping.
| Responses conversion and streaming receive one concrete
`OpenAIResponsesRequest`. |
| Anthropic request snapshots lived in generic tracing code. | Anthropic
request snapshots live with the protocol while generic tracing stays
protocol-independent. |
| Protocol tests and provider request doubles reflected the old API
ownership. | Protocol tests live under core and provider tests construct
real wire requests. |
| The API model package mixed protocol and model-catalog schemas. | The
API model package is removed, with catalog schemas beside catalog
construction and no compatibility shim. |
| Package version was `3.4.18`. | Package version is `3.4.19` with an
updated lockfile. |

<!-- greptile_comment -->

<details open><summary><h3>Greptile Summary</h3></summary>

This PR moves protocol request models to their protocol-owned packages.
The main changes are:

- Anthropic Messages models now live under `core.anthropic`.
- OpenAI Responses models now live under `core.openai_responses`.
- API handlers, routes, providers, and tests now use concrete protocol
request types.
- Anthropic request snapshots moved beside the Anthropic protocol
models.
- API model catalog schemas were kept with catalog response
construction.
- The package version and lockfile were updated.
</details>

<h3>Confidence Score: 5/5</h3>

This looks safe to merge.

No blocking issues were found in the changed code. Internal callers were
updated to pass the new concrete protocol models, and no stale internal
imports from the removed API model package were identified.

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 Pytest run for protocol ownership focused tests completed, showing
71 passed in 6.24s and EXIT\_CODE: 0.
- A protocol import smoke script was generated for the
import/conversion/trace workflow.
- The protocol import smoke run completed successfully, including model
ownership output, adapter payload evidence, and trace snapshot evidence,
with EXIT\_CODE: 0.

<a
href="https://app.greptile.com/trex/runs/14066157/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/core/anthropic/models.py | Anthropic wire request
and response models moved under the Anthropic protocol package. |
| src/free_claude_code/core/anthropic/native_messages_request.py |
Native Anthropic serialization now expects concrete `MessagesRequest`
instances. |
| src/free_claude_code/core/anthropic/conversion.py | OpenAI chat
conversion now reads fields directly from `MessagesRequest`. |
| src/free_claude_code/core/anthropic/request_snapshot.py | Anthropic
request snapshotting moved from generic tracing into the protocol
package. |
| src/free_claude_code/core/openai_responses/models.py | OpenAI
Responses ingress models moved under the Responses protocol package. |
| src/free_claude_code/core/openai_responses/input.py | Responses
conversion now consumes the concrete request model instead of a dumped
mapping. |
| src/free_claude_code/core/openai_responses/streaming/assembler.py |
Responses stream assembly now reads request attributes from
`OpenAIResponsesRequest`. |
| src/free_claude_code/api/routes.py | Routes now import protocol
request models from their new core owners. |
| src/free_claude_code/api/model_catalog.py | Model-list response
schemas now live with model catalog construction. |

</details>

<details open><summary><h3>Flowchart</h3></summary>

<a href="#gh-light-mode-only">

```mermaid
%%{init: {'theme': 'neutral'}}%%
flowchart LR
  API[API routes and handlers] --> Anthropic[core.anthropic models and helpers]
  API --> Responses[core.openai_responses models and adapter]
  Responses --> Anthropic
  Providers[Provider clients and transports] --> Anthropic
  Anthropic --> Trace[core.trace sanitization]
  API --> Catalog[api.model_catalog response schemas]
```

</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"}}}%%
flowchart LR
  API[API routes and handlers] --> Anthropic[core.anthropic models and helpers]
  API --> Responses[core.openai_responses models and adapter]
  Responses --> Anthropic
  Providers[Provider clients and transports] --> Anthropic
  Anthropic --> Trace[core.trace sanitization]
  API --> Catalog[api.model_catalog response schemas]
```

</a>
</details>

<sub>Reviews (1): Last reviewed commit: ["Move protocol models to their
protocol
o..."](https://github.com/alishahryar1/free-claude-code/commit/f1be5c1af4a10da710f80b5f9e7f6044a601f6af)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=43459428)</sub>

<!-- /greptile_comment -->
2026-07-10 19:26:27 -07:00
Ali Khokhar 4951983b5e Replace global runtime resources with explicit ownership (#1042)
## Problem

Provider, messaging, and transcription resources relied on
process-global state, leaving replacement, cancellation, and shutdown
ownership ambiguous. Separate server lifetimes could share
event-loop-bound resources or retain failed cleanup work.

## Changes

| Before | After |
| --- | --- |
| Provider clients found limiters through global singleton and scoped
registries. | Each provider instance receives and owns one explicitly
constructed limiter. |
| Messaging queues and voice pipelines relied on singleton or
module-global state. | Each platform owns its limiter and outbox, while
the application owns one injected transcriber. |
| Messaging shutdown mixed ingress, active work, delivery, and SDK
cleanup. | Application shutdown quiesces ingress, drains work, closes
delivery, then releases transcription and providers. |
| Cancelled or failed provider cleanup could be forgotten or treated as
complete. | The provider manager retains shielded generation and
unpublished-runtime cleanup until it succeeds. |
| Discord and Telegram startup tasks could outlive or poison runtime
readiness. | Platform runtimes observe long-lived tasks and retry only
independently repeatable lifecycle steps. |
| Constructor-captured security and diagnostic settings appeared
hot-applicable. | Admin marks those settings restart-required so applied
policy matches the running resource graph. |
| Lifecycle races lacked direct ownership coverage. | Deterministic
cancellation, retry, isolation, teardown, and live smoke contracts
protect the final ownership model. |

<!-- greptile_comment -->

<details open><summary><h3>Greptile Summary</h3></summary>

This PR moves runtime resources from global state into explicitly owned
application objects. The main changes are:

- Provider generations own their rate limiters and cleanup tasks.
- Messaging platforms own their limiter, outbox, ingress, and delivery
lifecycle.
- Application shutdown now runs through ordered cleanup gates.
- Voice transcription is injected as an owned runtime resource.
- Admin config marks constructor-captured settings as restart-required.
</details>

<h3>Confidence Score: 4/5</h3>

The shutdown path needs a bounded cleanup result before merging.

Cleanup steps that hang never reach the retryable incomplete-shutdown
path. ASGI shutdown can remain stuck while waiting for an external SDK,
transcriber, workflow, or provider cleanup. The retry ownership model
works only after cleanup returns or raises.

src/free_claude_code/runtime/application.py

<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**
- T-Rex ran the requested verification, but its local artifact
references were not uploaded.
- The validation run completed successfully with EXIT\_CODE: 0 and 62
tests passed in 3.91 seconds, using the command uv run pytest -vv
tests/runtime/test\_application\_runtime.py
tests/runtime/test\_provider\_manager.py
tests/providers/test\_provider\_runtime.py.

<a
href="https://app.greptile.com/trex/runs/14064214/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/runtime/application.py | Refactors shutdown into
ordered retryable cleanup gates, but cleanup awaitables can still block
shutdown forever. |
| src/free_claude_code/runtime/asgi.py | Reports incomplete runtime
shutdown when `close()` returns false. |
| src/free_claude_code/runtime/provider_manager.py | Adds owned provider
cleanup retry state and shielded generation cleanup. |

</details>

<a
href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22alishahryar1%2Ffree-claude-code%22%20on%20the%20existing%20branch%20%22refactor%2Fruntime-owned-resources%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22refactor%2Fruntime-owned-resources%22.%0A%0AFix%20the%20following%201%20code%20review%20issue.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%201%0Asrc%2Ffree_claude_code%2Fruntime%2Fapplication.py%3A59%0A**Cleanup%20Await%20Blocks%20Shutdown**%0A%0AWhen%20a%20platform%20SDK%20stop%2C%20workflow%20drain%2C%20transcriber%20close%2C%20or%20provider%20cleanup%20hangs%2C%20this%20helper%20waits%20forever%20and%20never%20returns%20%60False%60.%20ASGI%20shutdown%20stays%20stuck%20in%20%60runtime.close%28%29%60%20instead%20of%20reporting%20an%20incomplete%20shutdown%2C%20so%20the%20retained%20resource%20graph%20cannot%20be%20retried%20cleanly.%0A%0A&repo=alishahryar1%2Ffree-claude-code&pr=1042&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodexDark.svg?v=6"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"><img
alt="Fix All in Codex"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"></picture></a>

<sub>Reviews (2): Last reviewed commit: ["Report incomplete runtime
shutdown to
AS..."](https://github.com/alishahryar1/free-claude-code/commit/338b2bd179c3875b15bbd52818dd04c780e5d46d)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=43454593)</sub>

> Greptile also left **1 inline comment** on this PR.

**Context used:**

- Context used - CLAUDE.md
([source](https://app.greptile.com/alishahryar1/github/Alishahryar1/free-claude-code/-/custom-context?memory=d2fd24d8-0dec-4faf-8ee4-e085e215a2f8))

<!-- /greptile_comment -->
2026-07-10 18:46:50 -07:00
Ali Khokhar 160d63370b Establish single-owner runtime with stream-safe provider hot swaps (#1036)
## Problem

Provider runtime ownership was split between lifecycle code and mutable
FastAPI state, so Admin replacements could leak the new runtime,
double-close the old runtime, or close providers still serving active
streams. The API package also owned concrete process composition,
obscuring subsystem boundaries.

## Changes

| Before | After |
| --- | --- |
| FastAPI routes inspected several concrete `app.state` resources. |
FastAPI receives one explicit `ApiServices` boundary and stores only
`app.state.services`. |
| Admin Apply persisted config and directly replaced one runtime
reference. | Admin Apply validates a candidate, commits atomically, and
publishes it through the single runtime owner. |
| Provider replacement could close clients used by active streams. |
Generation leases retain old providers until each streaming or
non-streaming response finishes. |
| Provider generations owned discovery state and model metadata. |
`ProviderRuntimeManager` owns one application-lifetime catalog and one
discovery task across replacements. |
| API modules composed provider, messaging, and managed CLI resources. |
`runtime.bootstrap` composes concrete subsystems and
`ApplicationRuntime` owns their lifecycle. |
| Admin config, server URLs, and gateway model IDs lived under the API
package. | Admin config lives under `config`, server URLs live under
`config`, and gateway IDs live under `core`. |
| Messaging restoration and shutdown persistence were coordinated
externally. | `MessagingWorkflow` owns snapshot restoration and final
persistence flushing. |
| Hot-swap behavior lacked a real process-level race scenario. |
Deterministic ownership tests and a credential-free subprocess smoke
hold provider A while new requests switch to provider B. |
| Package version was `3.4.16`. | Package version is `3.4.17` with an
updated lockfile. |

<!-- greptile_comment -->

<details open><summary><h3>Greptile Summary</h3></summary>

This PR centralizes server runtime ownership and provider hot swaps. The
main changes are:

- Adds `ApplicationRuntime` and `ProviderRuntimeManager` as the process
owners.
- Moves FastAPI to an explicit `ApiServices` boundary.
- Retains provider generations until request and stream responses
finish.
- Moves admin config, server URL, and gateway model ID modules to
neutral package owners.
- Updates admin apply to validate, persist, and publish provider-only
changes through the runtime owner.
- Adds runtime ownership tests and a credential-free smoke scenario.
</details>

<h3>Confidence Score: 5/5</h3>

This looks safe to merge.

No blocking issues found in the changed code. The provider lease path
releases resources on normal completion, stream close, and cancellation.
The admin apply path keeps restart-required changes separate from
provider-only hot swaps, and repository import paths appear updated for
the moved modules.

No files need follow-up 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**
- Ran the T-Rex smoke test command and confirmed it completed with exit
code 0 and pytest passing.
- Monitored runtime ownership activity during the run, including a
provider A stream request on model-a generation 1, an admin publish to
generation 2, a new request on model-b generation 2, and the completion
of the original generation 1 stream.
- Collected smoke result artifacts from the .smoke-results area for
gateway 1, gateway 0, and main, and made them available for review.
- Opened the smoke report JSON artifacts to review the summarized
outcomes for each target environment.

<a
href="https://app.greptile.com/trex/runs/14008910/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/runtime/provider_manager.py | Adds provider
generation ownership, request leases, replacement, discovery refresh,
and shutdown cleanup. |
| src/free_claude_code/runtime/application.py | Adds the process-level
owner for startup, shutdown, admin operations, messaging, and session
control. |
| src/free_claude_code/api/routes.py | Routes now acquire provider
generation leases and bind them to response lifetime. |
| src/free_claude_code/api/response_streams.py | Adds response lifetime
binding so retained resources release after stream completion,
cancellation, or close. |
| src/free_claude_code/config/admin/persistence.py | Moves admin config
persistence into `config` and adds prepared validation plus atomic
managed-env commits. |
| src/free_claude_code/runtime/bootstrap.py | Adds the production
composition root for logging, runtime owners, services, and ASGI wiring.
|
| src/free_claude_code/api/__init__.py | Removes package-level API
re-exports as part of the HTTP adapter boundary cleanup. |

</details>

<details open><summary><h3>Sequence Diagram</h3></summary>

<a href="#gh-light-mode-only">

```mermaid
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant Client
participant API as FastAPI Route
participant Manager as ProviderRuntimeManager
participant Lease as Generation Lease
participant Runtime as Provider Generation
participant Admin as Admin Apply

Client->>API: Request /v1/messages or /v1/responses
API->>Manager: acquire()
Manager-->>API: lease for current generation
API->>Lease: resolve_provider()
Lease->>Runtime: use provider instance
Runtime-->>Client: response body or stream

Admin->>Manager: replace(candidate settings)
Manager->>Manager: publish new generation
Manager->>Manager: retire old generation

Client-->>API: response completes or disconnects
API->>Lease: release()
Lease->>Manager: decrement active leases
Manager->>Runtime: cleanup retired generation when drained
```

</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 Client
participant API as FastAPI Route
participant Manager as ProviderRuntimeManager
participant Lease as Generation Lease
participant Runtime as Provider Generation
participant Admin as Admin Apply

Client->>API: Request /v1/messages or /v1/responses
API->>Manager: acquire()
Manager-->>API: lease for current generation
API->>Lease: resolve_provider()
Lease->>Runtime: use provider instance
Runtime-->>Client: response body or stream

Admin->>Manager: replace(candidate settings)
Manager->>Manager: publish new generation
Manager->>Manager: retire old generation

Client-->>API: response completes or disconnects
API->>Lease: release()
Lease->>Manager: decrement active leases
Manager->>Runtime: cleanup retired generation when drained
```

</a>
</details>

<sub>Reviews (1): Last reviewed commit: ["refactor: establish
single-owner
applica..."](https://github.com/alishahryar1/free-claude-code/commit/92fc06aa733b7acc34ad6ea50de8b6b4ce5cfac1)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=43349002)</sub>

<!-- /greptile_comment -->
2026-07-10 10:52:54 -07:00
Ali Khokhar 1278d00873 Restore protocol-correct provider errors without client retry loops (#1033)
## Problem

Provider failures before streaming were converted to HTTP 200 SSE
errors, masking typed upstream statuses as malformed proxy responses.
This regressed #1026's error visibility while solving client retry
loops; fixes #1031.

## Changes

| Before | After |
| --- | --- |
| Pre-start Messages failures returned HTTP 200 SSE errors. | Pre-start
Messages failures return typed non-2xx JSON with `x-should-retry:
false`. |
| Non-streaming Messages could preserve partial content after an
internal stream error. | Non-streaming Messages discard partial content
and return the mapped Anthropic error. |
| Post-start failures could synthesize a successful stop lifecycle. |
Post-start failures emit protocol-native terminal errors without a fake
success stop. |
| Responses failures lacked consistent retry ownership and correlation.
| Responses failures retain typed envelopes, retry suppression, response
IDs, and request IDs. |
| Request IDs were generated independently across layers. | One
ingress-owned request ID flows through response headers, provider calls,
error bodies, and traces. |
| Provider exceptions owned Anthropic serialization. | Neutral Anthropic
utilities own error envelopes, status mapping, and redacted diagnostics.
|
| Failure-path smoke expected the regressed HTTP 200 shape. |
Failure-path smoke verifies typed JSON and one downstream Claude CLI
request. |
| Package metadata remained at 3.4.15. | Package metadata and the
lockfile advance to 3.4.16. |

<!-- greptile_comment -->

<details open><summary><h3>Greptile Summary</h3></summary>

This PR restores protocol-correct provider error handling for Messages
and Responses. The main changes are:

- Pre-start provider failures return typed JSON errors with retry
suppression.
- Streaming failures use protocol-native terminal events after commit.
- Request IDs now flow from ingress through headers, traces, provider
calls, and error bodies.
- Shared Anthropic and OpenAI error helpers now shape payloads and
redact diagnostics.
- Provider-error smoke coverage and package metadata were updated.
</details>

<h3>Confidence Score: 4/5</h3>

Committed streaming failure paths still expose exception-derived
messages to clients.

Pre-start provider error handling is more protocol-correct, and the
completed-message lifecycle conflict appears fixed.

Messages and Responses streams still need fixed safe messages after the
HTTP response has committed.

<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**
- I executed a focused uv-run harness against the Anthropic SSE
committed-stream path and reproduced a committed StreamingResponse that
yielded a terminal error SSE frame containing an internal diagnostic
marker.
- I ran a focused uv-run against iter\_responses\_sse\_from\_anthropic
and confirmed the stream was committed, with the later response.failed
SSE event carrying the internal diagnostic string in response.error.
- I completed provider error-handling verification, validating the
deterministic pytest path and running the local /v1/responses probe
script, which reported a 429 status with downstream\_call\_count: 1 and
related metadata, using the exact probe to exercise the failing
provider.

<a
href="https://app.greptile.com/trex/runs/13955393/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/api/response_streams.py | Pre-start Messages
errors now return typed JSON, but committed terminal SSE errors still
use exception-derived text. |
| src/free_claude_code/core/openai_responses/stream.py | Responses
streams now emit protocol failure events, but committed failures still
use exception-derived text. |
| src/free_claude_code/core/anthropic/streaming/ledger.py | Completed
Anthropic message streams now suppress late terminal errors after
`message_stop`. |
| src/free_claude_code/core/anthropic/errors.py | Shared Anthropic error
payload helpers now add request IDs, status mapping, and diagnostic
redaction. |

</details>

<a
href="https://app.greptile.com/api/ide/codex?prompt=IMPORTANT%3A%20Work%20in%20the%20repository%20%22alishahryar1%2Ffree-claude-code%22%20on%20the%20existing%20branch%20%22fix%2Fprotocol-correct-provider-errors%22.%20Checkout%20that%20branch%20%E2%80%94%20do%20NOT%20create%20a%20new%20branch%20or%20open%20a%20new%20PR.%20Push%20your%20changes%20to%20%22fix%2Fprotocol-correct-provider-errors%22.%0A%0AFix%20the%20following%202%20code%20review%20issues.%20Work%20through%20them%20one%20at%20a%20time%2C%20proposing%20concise%20fixes.%0A%0A---%0A%0A%23%23%23%20Issue%201%20of%202%0Asrc%2Ffree_claude_code%2Fapi%2Fresponse_streams.py%3A115-117%0A**Committed%20Stream%20Exception%20Text**%0A%0AWhen%20an%20Anthropic%20stream%20fails%20after%20the%20first%20chunk%20has%20committed%2C%20this%20terminal%20frame%20still%20derives%20the%20public%20SSE%20message%20from%20the%20exception.%20For%20unknown%20SDK%20or%20runtime%20errors%2C%20%60get_user_facing_error_message%28%29%60%20can%20return%20sanitized%20%60str%28exc%29%60%2C%20so%20internal%20URLs%2C%20payload%20fragments%2C%20or%20unsupported%20secret%20formats%20can%20still%20reach%20the%20client.%0A%0A%23%23%23%20Issue%202%20of%202%0Asrc%2Ffree_claude_code%2Fcore%2Fopenai_responses%2Fstream.py%3A49%0A**Failed%20Response%20Exception%20Text**%0A%0AAfter%20a%20Responses%20stream%20has%20emitted%20%60response.created%60%2C%20this%20failure%20event%20still%20uses%20exception-derived%20text%20as%20the%20public%20error%20message.%20If%20an%20unexpected%20provider%20or%20SDK%20exception%20includes%20internal%20diagnostics%20or%20a%20credential%20shape%20outside%20the%20redaction%20patterns%2C%20the%20committed%20%60response.failed%60%20event%20exposes%20it%20to%20the%20client.%0A%0A&repo=alishahryar1%2Ffree-claude-code&pr=1033&platform=github"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodexDark.svg?v=6"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"><img
alt="Fix All in Codex"
src="https://greptile-static-assets.s3.amazonaws.com/badges/FixAllInCodex.svg?v=6"></picture></a>

<sub>Reviews (2): Last reviewed commit: ["fix(streaming): ignore errors
after
mess..."](https://github.com/alishahryar1/free-claude-code/commit/157eb504e9c8e15f6591bd72391810610be078f7)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=43242122)</sub>

> Greptile also left **2 inline comments** on this PR.

**Context used:**

- Context used - CLAUDE.md
([source](https://app.greptile.com/alishahryar1/github/Alishahryar1/free-claude-code/-/custom-context?memory=d2fd24d8-0dec-4faf-8ee4-e085e215a2f8))

<!-- /greptile_comment -->
2026-07-10 01:08:21 -07:00
Ali Khokhar 3c9d0ced76 Simplify README around customer usage (#1032)
## Problem

The README mixed customer setup with provider internals and contributor
guidance, making installation and everyday usage harder to scan.

## Changes

| Before | After |
| --- | --- |
| Customer setup was spread across a 725-line README. | Customer setup
follows a clear install, configure, run, connect, and manage flow. |
| Providers used long implementation-oriented sections. | All 24
providers use a compact configuration table with essential notes. |
| Secondary clients and integrations filled the main scan path. |
Secondary clients and integrations use collapsible usage guides. |
| Development and contribution guidance lived in the customer README. |
Contributor guidance lives in `CONTRIBUTING.md`, with architecture
linked separately. |
| Internal capabilities were classified as README claims. | Internal
capabilities are classified as public-surface coverage and provider
documentation is contract-tested. |
| README simplification risked removing project identity and social
proof. | Existing badges, screenshot gallery, and Star History remain. |

<!-- greptile_comment -->

<details open><summary><h3>Greptile Summary</h3></summary>

This PR simplifies the customer README and moves contributor guidance
into a dedicated file. The main changes are:

- Shorter Quick Start, provider, client, integration, and management
sections in `README.md`.
- New `CONTRIBUTING.md` with setup, checks, standards, and versioning
guidance.
- Feature coverage reclassified from README claims to public-surface
coverage.
- A contract test for keeping the README provider table aligned with the
provider catalog.
</details>

<h3>Confidence Score: 5/5</h3>

This looks safe to merge.

No blocking issues found in the changed code.

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**
- Ran the Pytest-based docs contract checks and captured a log that
records the Pytest command, working directory, output, and exit code 0.
- Ran the Ruff-based docs contract validation and captured a log that
records the Ruff command, working directory, output, and exit code 0.

<a
href="https://app.greptile.com/trex/runs/13926440/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 |
|----------|----------|
| README.md | Reworked the README into a shorter customer setup and
usage guide. |
| CONTRIBUTING.md | Added contributor setup, quality checks, project
standards, and versioning guidance. |
| smoke/features.py | Moved several feature entries from README coverage
to public-surface coverage. |
| tests/contracts/test_feature_manifest.py | Added a provider table
contract test against the provider catalog. |

</details>

<sub>Reviews (1): Last reviewed commit: ["Simplify README around
customer
usage"](https://github.com/alishahryar1/free-claude-code/commit/ba0a7a837417b1566f071373d71ae14ecadfe5e7)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=43185730)</sub>

<!-- /greptile_comment -->
2026-07-09 18:19:01 -07:00
Ali Khokhar 85b601884d Remove legacy future annotation imports (#982)
## Problem

Python 3.14 provides native lazy annotations, but the codebase still
relied on legacy future annotation imports. Those imports also made
type-only import cycles easier to hide instead of fixing ownership
boundaries.

## Changes

| Before | After |
| --- | --- |
| Python files used `from __future__ import annotations`. | Python files
rely on Python 3.14 native lazy annotations. |
| Some runtime modules used `TYPE_CHECKING` or local imports for
required dependencies. | Runtime modules use top-level owner-module
imports with explicit boundaries. |
| Local and GitHub guardrails only rejected type ignore suppressions. |
Local and GitHub guardrails reject type ignore suppressions and legacy
future annotation imports. |
| Agent docs only documented the no-type-ignore rule. | Agent docs
document the Python 3.14 annotation and import-boundary rules. |

<!-- greptile_comment -->

<details open><summary><h3>Greptile Summary</h3></summary>

This PR moves the codebase to Python 3.14 native lazy annotations. The
main changes are:

- Removed legacy `from __future__ import annotations` imports across
Python modules.
- Promoted selected runtime dependencies from `TYPE_CHECKING` or local
imports to explicit owner-module imports.
- Added local, GitHub, and contract-test guardrails to reject legacy
future annotation imports.
- Updated agent docs with the annotation and import-boundary rules.
- Bumped the package patch version for production-file changes.
</details>

<h3>Confidence Score: 5/5</h3>

Safe to merge with low risk.

The changes are mostly mechanical annotation cleanup with matching CI
and contract-test guardrails. Reviewed import-boundary updates did not
show a confirmed runtime cycle or dependency break.

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**
- Performed an end-to-end validation of the guardrail contract suite: an
environment check confirmed uv availability, a guardrail pytest run used
CPython 3.14.0 with 5 passing contract tests, 3 focused CI-script tests
passed, and the direct CI suppressions guardrail command (including the
legacy future-annotations grep) also passed.

<a
href="https://app.greptile.com/trex/runs/13303335/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 |
|----------|----------|
| api/runtime.py | Moves messaging, CLI manager, session, limiter, and
tree dependencies from local/type-checking imports to explicit top-level
owner-module imports. |
| messaging/platforms/telegram.py | Removes future annotations and
promotes Telegram SDK type imports into the existing availability guard.
|
| messaging/platforms/telegram_inbound.py | Removes future annotations
and imports Telegram SDK types at module scope for inbound
normalization. |
| tests/contracts/test_import_boundaries.py | Adds an AST contract that
rejects legacy future annotation imports across Python files. |
| scripts/ci.sh | Extends the local suppression check to reject legacy
future annotation imports alongside type-ignore suppressions. |
| scripts/ci.ps1 | Mirrors the local PowerShell CI suppression check for
legacy future annotations. |
| .github/workflows/tests.yml | Renames and broadens the GitHub
guardrail job to reject both type suppressions and legacy future
annotations. |
| pyproject.toml | Bumps the patch version for production-file changes.
|

</details>

<details open><summary><h3>Sequence Diagram</h3></summary>

<a href="#gh-light-mode-only">

```mermaid
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant Dev as Developer/CI
participant Guard as Suppression guard
participant AST as Import-boundary contract test
participant Py as Python modules

Dev->>Guard: Run local/GitHub suppression check
Guard->>Py: "Scan *.py for type ignores and future annotations"
Guard-->>Dev: Fail if legacy annotation import remains
Dev->>AST: Run pytest contract tests
AST->>Py: Parse imports with ast
AST-->>Dev: Assert no future annotations/import-boundary violations
Py-->>Dev: Use Python 3.14 native lazy annotations
```

</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 Dev as Developer/CI
participant Guard as Suppression guard
participant AST as Import-boundary contract test
participant Py as Python modules

Dev->>Guard: Run local/GitHub suppression check
Guard->>Py: "Scan *.py for type ignores and future annotations"
Guard-->>Dev: Fail if legacy annotation import remains
Dev->>AST: Run pytest contract tests
AST->>Py: Parse imports with ast
AST-->>Dev: Assert no future annotations/import-boundary violations
Py-->>Dev: Use Python 3.14 native lazy annotations
```

</a>
</details>

<sub>Reviews (2): Last reviewed commit: ["Remove legacy future
annotations
import"](https://github.com/alishahryar1/free-claude-code/commit/6e6cda69da243bbdb92831207aecb3731ad469f8)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=41875785)</sub>

<!-- /greptile_comment -->
2026-07-04 21:41:51 -07:00
Ali Khokhar 58aef0dc8a Refactor provider runtime ownership (#925)
## Problem

Provider construction, model discovery, validation, and cleanup lived in
one registry module. API and admin routes depended on registry-shaped
app state and legacy process-level provider helpers.

## Changes

| Before | After |
| --- | --- |
| `providers.registry` mixed provider factories, config, cache,
discovery, validation, and cleanup. | `providers.runtime` splits
factories, config, cache, model cache, discovery, validation, and
runtime orchestration. |
| API and admin routes read `app.state.provider_registry` and sometimes
created registries ad hoc. | API and admin routes use app-scoped
`ProviderRuntime` through `app.state.provider_runtime`. |
| `api.dependencies` kept process-global provider cache helpers. |
`api.dependencies` resolves providers only through the app-scoped
runtime. |
| Registry-shaped tests preserved old internal boundaries. |
Runtime-shaped tests assert provider config, construction, cache,
discovery, validation, and import boundaries. |

<!-- greptile_comment -->

<details open><summary><h3>Greptile Summary</h3></summary>

This PR moves provider lifecycle ownership from the old registry module
into an app-scoped runtime package. The main changes are:

- Split provider config, factory wiring, instance cache, model cache,
discovery, validation, and cleanup into `providers.runtime` modules.
- Updated API and admin routes to resolve providers and model metadata
through `app.state.provider_runtime`.
- Removed legacy process-global provider helpers and the deleted
`providers.registry` module.
- Updated docs, smoke metadata, import-boundary checks, and tests for
the new runtime ownership model.
- Bumped the package version and lockfile metadata for the production
refactor.
</details>

<h3>Confidence Score: 5/5</h3>

The provider runtime refactor appears merge-safe with no identified
blocking issues.

The changes consistently move provider ownership to app-scoped runtime
modules and update API, admin, docs, smoke metadata, import-boundary
checks, and tests around that architecture.

<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**
- Ran a baseline and head comparison of provider registry and runtime
states, verifying the after-state shows head
state\_has\_provider\_registry=False and
state\_has\_provider\_runtime=True, that GET /v1/models and admin
endpoints respond with 200, and that provider\_resolver\_called via
runtime, with assertions passing.
- Verified that the four focused provider-runtime contract tests passed
in both the before and after refactor runs, including runtime split
checks, with exit code 0.
- Identified environmental blockers that prevented the smoke-runtime
workflow from running, including uv unavailability, missing pytest for
/usr/local/bin/python, and Python 3.11 being used despite pyproject.toml
requiring \>=3.14.

<a
href="https://app.greptile.com/trex/runs/12528505/artifacts"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifactsDark.svg?v=1"><source
media="(prefers-color-scheme: light)"
srcset="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=1"><img
alt="View all artifacts"
src="https://greptile-static-assets.s3.amazonaws.com/badges/ViewAllArtifacts.svg?v=1"
height="32"></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>

<sub>Reviews (1): Last reviewed commit: ["Refactor provider runtime
ownership"](https://github.com/alishahryar1/free-claude-code/commit/01d589488185c1f85112f1a49c47f04512846161)
| [Re-trigger
Greptile](https://app.greptile.com/api/retrigger?id=40312173)</sub>

<!-- /greptile_comment -->
2026-06-27 15:04:34 -07:00
Ali Khokhar 6bee3104fe Refactor CLI surfaces around launchers and managed Claude (#861)
## 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. |
2026-06-18 18:36:37 -07:00
Ali Khokhar 8d2e5b95f7 Refactor OpenAI Responses into modular adapter facade (#847)
## Summary

- Split monolithic `core/openai_responses/conversion.py` and `sse.py`
into focused protocol modules (input, output, stream, tools, reasoning,
events, etc.) behind an `OpenAIResponsesAdapter` facade.
- Wire `ClaudeProxyService.create_response()` through the adapter
instead of importing conversion helpers directly, tightening the
API/import boundary.
- Add Codex bridging for Responses `custom_tool_call` items and document
the adapter architecture in `ARCHITECTURE.md`.

## Test plan

- [x] `uv run pytest tests/core/openai_responses/
tests/api/test_openai_responses.py tests/cli/test_adapters.py
tests/contracts/test_import_boundaries.py`
- [x] Full CI via `.\scripts\ci.ps1`
2026-06-17 20:19:51 -07:00
Alishahryar1 b26957faaf Update README 2026-06-16 17:01:24 -07:00
Ali Khokhar 3abe41d270 Add Codex support (#691) 2026-06-16 16:32:43 -07:00
Alishahryar1 044a152fb4 Add Gemini thought signature smoke 2026-05-31 15:26:13 -07:00
Alishahryar1 de8e902899 Add Claude CLI smoke matrices 2026-05-09 17:27:23 -07:00
Alishahryar1 07497c7ed8 Add NVIDIA NIM CLI smoke matrix and tool schema aliasing 2026-05-09 14:25:50 -07:00
Alishahryar1 2d2bf3de70 fix: replay reasoning_content for DeepSeek/NIM and expand provider smoke
- Add ReasoningReplayMode and top-level reasoning replay in OpenAI conversion
- DeepSeek/NIM request bodies use reasoning_content when thinking is enabled
- NIM retries without reasoning_content on 400 from upstream
- Per-provider smoke models (FCC_SMOKE_MODEL_*) independent of MODEL mapping
- Fix smoke model override parsing for owner/model names with slashes
- Live smoke: reasoning tool continuation uses synthetic thinking+tool history
- Tests and docs updated
2026-04-26 11:02:18 -07:00
Wang Ji b525217633 [feat] ollama method support (#129)
Support use ollama method like LM stuio

---------

Co-authored-by: Alishahryar1 <alishahryar2@gmail.com>
Co-authored-by: u011436427 <u011436427@noreply.gitcode.com>
2026-04-25 22:06:36 -07:00
Alishahryar1 f29e693dc5 Add per-model thinking toggles 2026-04-25 20:51:07 -07:00
Alishahryar1 0e3b2c24b4 refactor: remove OpenRouter rollback, shims, and redundant layers
- OpenRouter: native Anthropic only; remove chat_request and OPENROUTER_TRANSPORT
- Drop OpenAICompatibleProvider alias, api.request_utils, voice_pipeline facade
- Simplify OpenRouter SSE, generic reasoning in conversion, messaging dispatch
- Shared markdown table helpers; API optimization response helper; contract guards
- Restore PLAN.md; update docs and tests
2026-04-24 21:08:38 -07:00
Alishahryar1 66ef23072c Refactor provider routing and smoke coverage 2026-04-24 19:34:34 -07:00
Alishahryar1 751694a5da Refactor smoke testing framework and enhance provider configurations
- Updated DEFAULT_TARGETS in config.py to include new targets: clients, llamacpp, and lmstudio, while removing contract and optimizations.
- Introduced TARGET_ALIASES for better target management.
- Added TARGET_REQUIRED_ENV to specify environment variables needed for each target.
- Enhanced SmokeOutcome in report.py to include classification of outcomes for better reporting.
- Implemented classify_outcome function to categorize smoke test results.
- Added new test for stop endpoint in test_api_live.py to ensure proper error handling.
- Updated test_auth_live.py to enforce auth token requirements and utilize environment files.
- Changed target from vscode to clients in test_client_shapes_live.py.
- Removed obsolete test_feature_manifest.py and test_stream_contracts.py files.
- Added new skip helpers in skips.py to manage upstream unavailability scenarios.
- Created new tests for local provider endpoints in test_local_provider_endpoints_live.py.
- Added comprehensive feature inventory tests in tests/contracts/test_feature_manifest.py.
- Implemented stream contract tests in tests/contracts/test_stream_contracts.py.
2026-04-24 17:16:06 -07:00
Ali Khokhar 462a9430bb Add local live smoke test suite (#148)
## Summary
- add an opt-in local `smoke/` pytest suite for API, auth, providers,
CLI, IDE-shaped requests, messaging, voice, tools, and thinking stream
contracts
- keep smoke tests out of normal CI collection with `testpaths =
["tests"]`
- write sanitized smoke artifacts under `.smoke-results/`

## Verification
- `uv run ruff format`
- `uv run ruff check`
- `uv run ty check`
- `uv run ty check smoke`
- `FCC_LIVE_SMOKE=1 FCC_SMOKE_TARGETS=all FCC_SMOKE_RUN_VOICE=1 uv run
pytest smoke -n 0 -m live -s --tb=short` -> 17 passed, 9 skipped
- `uv run pytest` -> 904 passed

## Notes
- Skipped live checks require local credentials/tools/services, such as
provider models, Telegram/Discord targets, voice backend, or Claude CLI.
- `claude-pick` smoke was intentionally removed.
2026-04-23 19:06:09 -07:00