Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
3566bce
feat(fp-cli): open-source the Cloud CLI as `fp-cli`, command `fp`
NiveditJain Aug 17, 2026
e4f8890
docs(changelog): record the fp-cli open-sourcing (#702)
NiveditJain Aug 17, 2026
c4d9a71
feat(fp-cli): re-establish the agent-skill mirror, now as skills/fp-cli
NiveditJain Aug 17, 2026
ae14887
fix(fp-cli): remove a customer identifier, restore publish authorization
NiveditJain Aug 17, 2026
29d04e8
fix(fp-cli): stop a stdin read draining a query, and a tripwire namin…
NiveditJain Aug 17, 2026
7900b01
chore: re-trigger CI after GitHub 429s in Set up job
NiveditJain Aug 17, 2026
dc6364e
chore: re-trigger CI again — GitHub Actions still in a partial outage
NiveditJain Aug 17, 2026
80affea
chore: re-trigger CI (attempt 4) — one job per run still losing setup…
NiveditJain Aug 17, 2026
7670c90
feat(sdk): open-source the telemetry SDK as `failproofai-sdk` in sdk/…
NiveditJain Aug 17, 2026
cd52279
fix(sdk): make the zero-dependency check work on Python 3.10
NiveditJain Aug 17, 2026
7691199
test(sdk): stop the configure() thread-safety test depending on execu…
NiveditJain Aug 17, 2026
3b302ca
fix(sdk): address four CodeRabbit findings — all four were real
NiveditJain Aug 17, 2026
bc039ac
fix(fp-cli): two docs claims that contradict the shipped code
NiveditJain Aug 17, 2026
b30c492
fix(fp-cli): two --help examples that fail when you run them
SiddarthAA Aug 18, 2026
10364f3
fix(sdk): seven ways the SDK lost events without saying so
SiddarthAA Aug 18, 2026
18ef5c3
feat(fp-cli): move the session into ~/.failproofai/fpcli/cli-auth.json
SiddarthAA Aug 18, 2026
acfca52
fix(fp-cli): name the right stale session file for FP_HOME users
SiddarthAA Aug 18, 2026
e3c7e71
fix(fp-cli): three help strings still printed the pre-move config path
SiddarthAA Aug 18, 2026
ce2012d
feat(fp-cli): adopt a pre-move session instead of signing the machine…
SiddarthAA Aug 18, 2026
3b3d666
test(fp-cli): adoption must not resurrect a session after logout
SiddarthAA Aug 18, 2026
5bacab7
fix(sdk): stop the test suite writing into the developer's real spool
SiddarthAA Aug 18, 2026
33cc78a
feat(sdk)!: default the spool to ~/.failproofai/custom-agents
SiddarthAA Aug 18, 2026
d1b16b1
Merge origin/main into feat/fp-cli
SiddarthAA Aug 18, 2026
2fa3e57
test(sdk): pin what the SDK may create inside ~/.failproofai
SiddarthAA Aug 18, 2026
cc28451
fix(sdk): four review findings — durability, u32 range, NaN, cancella…
SiddarthAA Aug 18, 2026
c99dc2d
fix(sdk): five bugs found by adversarial testing, two of them crashes
SiddarthAA Aug 18, 2026
2fe57f4
test(sdk): stop the spool-contract test aborting the suite outside th…
SiddarthAA Aug 18, 2026
bb1cc99
test(fp-cli): guard the credential path against drifting from the reg…
SiddarthAA Aug 19, 2026
3c8bc31
[fp-cli] fp policies, fp fleet and fp guardrails — the dashboard's en…
SiddarthAA Aug 19, 2026
7215375
Merge origin/main into feat/fp-cli
SiddarthAA Aug 20, 2026
ee735f5
[sdk] Native support for LangChain/LangGraph, CrewAI, LlamaIndex and …
SiddarthAA Aug 20, 2026
84a7b3c
ci: ignore an unfixable chromadb advisory that cannot reach a user
SiddarthAA Aug 20, 2026
ae10911
docs(changelog): one Docs section per version, not two
SiddarthAA Aug 20, 2026
6d416b4
ci: ignore the advisory under its primary id, not only its alias
SiddarthAA Aug 20, 2026
3a0e57b
ci: make the root osv-scanner.toml govern every lockfile it scans
SiddarthAA Aug 20, 2026
0c0ff4c
fix(fp-cli): stop the customer tripwire from publishing the name it h…
SiddarthAA Aug 20, 2026
e3271fc
docs(sdk): correct the spool root the README tells readers to look in
SiddarthAA Aug 20, 2026
9bbccaa
fix(failproofaid): --help printed nothing and started the daemon
SiddarthAA Aug 20, 2026
320598a
ci(sdk): actually run the framework integration suites
SiddarthAA Aug 20, 2026
ad48c92
chore(fp-cli): stop fixtures and help text naming a real domain
SiddarthAA Aug 20, 2026
f1e68f7
fix(fp-cli): `fp issues show <malformed-id>` never reached its not-fo…
SiddarthAA Aug 20, 2026
de388b1
fix(collect): park a batch the server stored none of, instead of dele…
SiddarthAA Aug 20, 2026
6372ecf
fix(fp-cli): resolve a member by the email the caller actually typed
SiddarthAA Aug 20, 2026
b672543
fix(sdk): document model_response's real keyword, and guard the class
SiddarthAA Aug 20, 2026
bed3d39
docs(integrations): let the page shape match what is being explained
SiddarthAA Aug 20, 2026
ab4d76c
docs(skill): correct three stale claims, and guard the prose
SiddarthAA Aug 20, 2026
d7dd7cc
fix(sdk): stop $AGENTEYE_HOME from moving the spool off the umbrella
SiddarthAA Aug 20, 2026
a720f38
fix(fp-cli): sum every policy source in the decision timeline, not se…
SiddarthAA Aug 20, 2026
9634840
docs(cloud-cli): stop denying commands the CLI has, and name the real…
SiddarthAA Aug 20, 2026
362de76
docs(fp-cli): compose needs policies:write, not agent:use
SiddarthAA Aug 20, 2026
95e4b24
feat(sdk): raise LangChain's capture limit, and tie the event budget …
SiddarthAA Aug 21, 2026
05b47fa
Merge origin/main into feat/fp-cli
NiveditJain Aug 21, 2026
45a1faf
fix(sdk): stop the shipped SIGTERM recipe from deadlocking the host p…
SiddarthAA Aug 24, 2026
4737073
fix(sdk): make the adapters' size budget, privacy switch and error ac…
SiddarthAA Aug 24, 2026
e6025f7
fix(sdk): stop the sdist poisoning a real spool, and make four guards…
SiddarthAA Aug 24, 2026
7c4c10f
fix(fp-cli): stop the CLI reporting success it did not have, and leak…
SiddarthAA Aug 24, 2026
f16eae8
fix(collect): stop the delivery-health signal reporting success while…
SiddarthAA Aug 24, 2026
790a7b0
docs: correct nine claims the code disproves, and guard the two that …
SiddarthAA Aug 24, 2026
e354054
ci: make the publish gate test the adapters, and the workflow guards …
SiddarthAA Aug 24, 2026
aa87d6a
docs(changelog): record the review fixes under 1.0.2-beta.0
SiddarthAA Aug 24, 2026
236534f
fix(fp-cli): relock for the corrected typer floor
SiddarthAA Aug 24, 2026
01f6799
Merge remote-tracking branch 'origin/main' into feat/fp-cli
SiddarthAA Aug 24, 2026
bd9b68e
Merge remote-tracking branch 'origin/feat/fp-cli' into feat/fp-cli
SiddarthAA Aug 24, 2026
4ce3b58
fix(sdk): bound the queue by measured bytes, and stop an oversized ev…
SiddarthAA Aug 24, 2026
e4b51bf
fix(collect): stop a partially-accepted batch destroying the events i…
SiddarthAA Aug 24, 2026
21cec5b
fix(fp-cli): stop a failed membership lookup reading as "you belong t…
SiddarthAA Aug 24, 2026
915a592
ci: keep the publishing identity and the mirror's code out of the sam…
SiddarthAA Aug 24, 2026
35c4d52
docs(changelog): record the second-review fixes
SiddarthAA Aug 24, 2026
8306b91
fix(fp-cli): stop a busy machine being reported as a broken policy
SiddarthAA Aug 24, 2026
2f18ac4
chore(release): open both Python packages at 0.0.1b1
NiveditJain Aug 24, 2026
51738dd
feat(ci): version management pipelines for fp-cli and failproofai-sdk
NiveditJain Aug 24, 2026
01977ab
docs(claude): record the Python packages' release scheme
NiveditJain Aug 24, 2026
cc9a710
fix(ci): close the re-run bypass in the PyPI publish guard
NiveditJain Aug 24, 2026
8762e27
fix(sdk): stop the writer thread flushing into whichever test is running
NiveditJain Aug 24, 2026
9c81113
docs(ci): point PyPI setup at the page that exists for an unregistere…
NiveditJain Aug 24, 2026
2ecb250
feat(ci): GitHub Releases and changelogs for both Python packages
NiveditJain Aug 24, 2026
e385535
refactor: rename the Cloud CLI distribution to fp-cloud-cli
NiveditJain Aug 24, 2026
60f4dc8
docs: restructure the agent-instrumentation docs, and make the star c…
SiddarthAA Aug 24, 2026
dd8cf5a
Merge remote-tracking branch 'origin/feat/fp-cli' into feat/fp-cli
SiddarthAA Aug 24, 2026
146cacf
fix(docs): move the 14 locale SDK reference copies with their English…
NiveditJain Aug 24, 2026
dac8639
test: cover the live star count and the Python package registration
NiveditJain Aug 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
32 changes: 32 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,35 @@ updates:
rust-dependencies:
patterns:
- "*"

# The `fp` CLI (PyPI: fp-cloud-cli) — the only Python in the repo. Its lockfile is
# `fp-cloud-cli/uv.lock`, so the ecosystem is `uv`, and the directory is the package
# root rather than `/`. Grouped for the same reason as the Rust tree: the whole
# dependency set is verified together by one pytest run, and separate PRs each
# rebuild the lockfile the others just changed.
- package-ecosystem: uv
directory: /fp-cloud-cli
schedule:
interval: weekly
day: monday
open-pull-requests-limit: 5
groups:
python-dependencies:
patterns:
- "*"

# The telemetry SDK (PyPI: failproofai-sdk). Its own lockfile and its own uv
# ecosystem entry — dependabot resolves per directory, so fp-cloud-cli's entry above
# does not see this tree at all. The only things in the lockfile are the test
# runner and its transitive deps: the package itself declares NO runtime
# dependencies, and `tests/test_zero_dependencies.py` fails if that changes.
- package-ecosystem: uv
directory: /sdk/python
schedule:
interval: weekly
day: monday
open-pull-requests-limit: 5
groups:
python-dependencies:
patterns:
- "*"
229 changes: 228 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,14 @@ name: CI
on:
push:
branches: [main]
# `main` AND the long-lived branches other PRs stack onto. A pull request is
# tested against the branch it will actually merge into, and a stacked PR
# targeting anything but `main` matched nothing here — so #730, thirty commits
# of SDK work, ran no unit tests, no build and no lint at all. The only signal
# it produced was the daemon cross-compile, and only because it touched
# `crates/`. A PR that cannot go red is not a reviewed PR.
pull_request:
branches: [main]
branches: [main, feat/fp-cli]

concurrency:
group: ci-${{ github.ref }}
Expand Down Expand Up @@ -257,6 +263,227 @@ jobs:
if: steps.crates.outputs.present == 'true'
run: cargo test --workspace

# The `fp` CLI (PyPI: fp-cloud-cli). The only Python in this repo, and the only job that
# tests it — none of the bun/cargo jobs above look at fp-cloud-cli/ at all. It is matrixed
# across the Python versions pyproject.toml's requires-python advertises, because
# claiming >=3.10 and testing only one of them is how a 3.10 user finds the break.
#
# That comment was true of the SDK's matrix and not of this one, which ran 3.10
# and 3.13 only while the classifiers claimed 3.10–3.13 — so a resolver picking
# a different transitive set on 3.11 or 3.12 broke those users with fully green
# CI and a wheel whose own metadata said they were supported. All four now, and
# `__tests__/ci/fp-cloud-cli-workflows.test.ts` pins the list against the classifiers
# so the two cannot drift apart again.
fp-cloud-cli:
runs-on: ubuntu-latest
# a uv sync plus pytest across four interpreters; the bound exists so a stalled
# package mirror cannot hold a release for six hours (#726).
timeout-minutes: 15
defaults:
run:
working-directory: fp-cloud-cli
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v7.0.1

- uses: astral-sh/setup-uv@v7
with:
enable-cache: true
cache-dependency-glob: fp-cloud-cli/uv.lock

- name: Install dependencies
run: uv sync --locked --extra dev --python ${{ matrix.python-version }}

# FP_CLI_REQUIRE_CONTRACT makes test_fp_home_contract.py FAIL rather than skip
# when it cannot read src/hooks/fp-home.ts. That file is the register for a
# home this CLI writes a credential into, and the assertions against it are
# the only thing keeping the two sides from drifting — before they existed, a
# rename on either side left both suites green. A guard that can quietly
# degrade to a skip is the same guard the SDK's spool contract used to be.
- name: Test
env:
FP_CLI_REQUIRE_CONTRACT: "1"
run: uv run pytest tests/ -q

- name: Build the distribution
run: uv build

# A stale `include = [...]` in [tool.setuptools.packages.find] builds a
# SUCCESSFUL but EMPTY wheel — pip installs it and the console script then
# ImportErrors. Nothing else in this job would notice, so assert the payload.
- name: Verify the wheel actually contains the package
run: |
python3 - <<'PY'
import glob, sys, zipfile
wheel = glob.glob("dist/*.whl")[0]
names = zipfile.ZipFile(wheel).namelist()
modules = [n for n in names if n.startswith("fp_cli/") and n.endswith(".py")]
print(f"{wheel}: {len(modules)} modules")
if len(modules) < 20:
sys.exit(f"wheel looks empty — only {len(modules)} modules under fp_cli/")
PY

# `fp` is the contract users type. Prove the entry point resolves from a clean
# install of the built artifact, not from the source tree.
- name: Smoke-test the installed console script
run: |
uv venv /tmp/fp-smoke
VIRTUAL_ENV=/tmp/fp-smoke uv pip install dist/*.whl
/tmp/fp-smoke/bin/fp --version
/tmp/fp-smoke/bin/fp help > /tmp/fp-help.txt
if grep -qi agenteye /tmp/fp-help.txt; then
echo '::error::retired product name present in the fp help output'
exit 1
fi

# The telemetry SDK (PyPI: failproofai-sdk, import failproofai_sdk). Second Python
# component, sibling of fp-cloud-cli above, and deliberately its own job: it shares no
# lockfile, no dependencies and no release cadence with the CLI.
#
# The matrix is wider than fp-cloud-cli's two versions on purpose. This package declares
# no dependencies at all, so it has no third-party floor quietly constraining which
# interpreters it is really exercised on — and it is installed into other people's
# agent processes, whose Python version we do not choose. Every version
# requires-python advertises is tested.
failproofai-sdk:
runs-on: ubuntu-latest
# the same, across five — every version requires-python advertises; the bound exists so a stalled
# package mirror cannot hold a release for six hours (#726).
timeout-minutes: 10
defaults:
run:
working-directory: sdk/python
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
steps:
- uses: actions/checkout@v7.0.1

- uses: astral-sh/setup-uv@v7
with:
enable-cache: true
cache-dependency-glob: sdk/python/uv.lock

- name: Install dependencies
run: uv sync --locked --extra dev --python ${{ matrix.python-version }}

# FAILPROOFAI_SDK_REQUIRE_CONTRACT makes test_spool_contract.py FAIL rather than
# skip when it cannot find crates/fpai-collect or src/hooks/fp-home.ts. Those
# assertions are the only check that this SDK writes where the daemon reads, and
# a guard that can silently degrade to a skip is not a guard — its predecessor in
# the agenteye repo skipped in every CI run for exactly this reason.
- name: Test
env:
FAILPROOFAI_SDK_REQUIRE_CONTRACT: "1"
run: uv run pytest tests/ -q

- name: Build the distribution
run: uv build

# A stale `include = [...]` in [tool.setuptools.packages.find] builds a
# SUCCESSFUL but EMPTY wheel — pip installs it and the import then fails.
# py.typed goes the same way if package-data stops naming it, and nothing
# else in this job would notice either. Assert the payload.
- name: Verify the wheel actually contains the package
run: |
python3 - <<'PY'
import glob, sys, zipfile
wheel = glob.glob("dist/*.whl")[0]
names = zipfile.ZipFile(wheel).namelist()
modules = [n for n in names if n.startswith("failproofai_sdk/") and n.endswith(".py")]
print(f"{wheel}: {len(modules)} modules")
if len(modules) < 7:
sys.exit(f"wheel looks empty — only {len(modules)} modules under failproofai_sdk/")
if not any(n.endswith("py.typed") for n in names):
sys.exit("py.typed is missing from the wheel — the type hints do not count without it")
if not any(n.endswith("LICENSE") for n in names):
sys.exit("LICENSE is missing from the wheel")
PY

# `--no-deps` is the assertion, not an optimisation. "Zero dependencies" is the
# reason this package is safe to drop into someone else's agent, so prove it
# against the built artifact rather than the source tree: install it with nothing
# else present, emit real events, and read them back off disk.
- name: Smoke-test the installed package with no dependencies
run: |
uv venv /tmp/sdk-smoke
VIRTUAL_ENV=/tmp/sdk-smoke uv pip install --no-deps dist/*.whl
FAILPROOFAI_HOME=/tmp/sdk-spool /tmp/sdk-smoke/bin/python -c "
import failproofai_sdk as s
print(s.__version__)
s.event.agent_start(session_id='smoke', agent_id='a', goal='ci')
s.event.tool_use(session_id='smoke', agent_id='a', tool_name='t', tool_call_id='c')
s.event.tool_result(session_id='smoke', agent_id='a', tool_name='t', tool_call_id='c', output='ok')
"
python3 - <<'PY'
import glob, json, sys
# $FAILPROOFAI_HOME/custom-agents/events — the `custom-agents` segment
# is appended unconditionally by the resolver, which is what makes the
# spool impossible to place outside the umbrella.
batches = glob.glob("/tmp/sdk-spool/custom-agents/events/*.jsonl")
if not batches:
sys.exit("the installed wheel wrote no event batch")
events = [json.loads(line) for p in batches for line in open(p) if line.strip()]
types = {e["type"] for e in events}
if types != {"agent_start", "tool_use", "tool_result"}:
sys.exit(f"unexpected events from the installed wheel: {sorted(types)}")
# Emitted by the artifact, so this also proves the wire format survived
# packaging rather than only surviving an in-tree import.
if not all("environment" in e for e in events):
sys.exit("an event reached disk without the `environment` field")
print(f"{len(events)} events written by the installed artifact")
PY

# The adapters' ONLY automated evidence. It is a separate job, not a leg of the
# matrix above, because installing five agent frameworks costs minutes and gains
# nothing from being repeated across five interpreters — the adapters bind to
# framework APIs, not to interpreter version.
#
# WHY THIS EXISTS: tests/integrations/* already honour
# AGENTEYE_TESTS_REQUIRE_FRAMEWORKS, and their comments say "CI leg sets
# AGENTEYE_TESTS_REQUIRE_FRAMEWORKS=1". No such leg was ever added, and the
# frameworks live in extras that `--extra dev` does not pull, so all four
# modules skipped at import in every run: 168 test functions across 6,071 lines,
# green, never executed. An adapter could break against a new framework release
# and nothing here would say so. That is the same "a guard that can silently
# degrade to a skip is not a guard" this file already hardened
# test_spool_contract.py against — the integration suites were simply missed.
failproofai-sdk-integrations:
runs-on: ubuntu-latest
timeout-minutes: 20
defaults:
run:
working-directory: sdk/python
steps:
- uses: actions/checkout@v7.0.1

- uses: astral-sh/setup-uv@v7
with:
enable-cache: true
cache-dependency-glob: sdk/python/uv.lock

# Every framework extra. `--locked` keeps this honest: the lockfile already
# resolves all five, so a drift here fails rather than silently re-resolving.
- name: Install dependencies (all framework extras)
run: >-
uv sync --locked --extra dev
--extra langchain --extra langgraph --extra crewai
--extra llamaindex --extra pydantic-ai
--python 3.12

# AGENTEYE_TESTS_REQUIRE_FRAMEWORKS turns each module's import skip into a
# hard failure. Without it a botched install above would read as "4 skipped"
# and the job would pass having tested nothing — which is exactly the state
# this job was added to end.
- name: Test the framework adapters
env:
AGENTEYE_TESTS_REQUIRE_FRAMEWORKS: "1"
run: uv run pytest tests/integrations -q

test:
runs-on: ubuntu-latest
# The retry above nominally allows 3 attempts x 10 minutes. Capping the job
Expand Down
10 changes: 10 additions & 0 deletions .github/workflows/osv-scanner.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,19 @@ jobs:
id: scan
uses: google/osv-scanner-action/osv-scanner-action@f4cfcc01edc9c8b756a9b873b7a623ca674da51e # v2.3.8
with:
# `--config` is load-bearing, not tidiness. Without it the scanner
# resolves a config PER SCANNED FILE, relative to that file — so the
# root `osv-scanner.toml` governed `bun.lock` and `Cargo.lock` and
# reached neither `uv.lock`. An ignore written for a finding in
# `sdk/python/uv.lock` loaded, filtered nothing, and was reported as
# an "unused ignore" while the gate stayed red. Naming it once makes
# one allow-list authoritative for every lockfile below.
scan-args: |-
--config=osv-scanner.toml
--lockfile=bun.lock
--lockfile=Cargo.lock
--lockfile=fp-cloud-cli/uv.lock
--lockfile=sdk/python/uv.lock
# Only the schedule run notifies — nothing on main touched the lockfile,
# so nobody is watching it the way a PR author watches their own checks
# or a push failure shows up against the commit they just merged. Same
Expand Down
Loading