DEV Community

Indu Das
Indu Das

Posted on

FreshCtx 0.3.0: What changed after developers tested the stale-context boundary

FreshCtx 0.3.0 is now public.

The first release started with a narrow problem:

An AI agent can make a reasonable decision from accurate information, then act incorrectly because that information changed before execution.

The early implementation proved that FreshCtx could declare the evidence used during reasoning, revalidate it at the action boundary and block an action when the evidence was no longer current.

The questions developers asked after launch were more practical:

  • What happens when several dependencies must be checked?
  • Does revalidation add too much latency?
  • What if a source is slow or rate-limited?
  • Can it work inside an async agent?
  • What happens when the local database is upgraded or damaged?
  • How can an independent developer record what a test actually proved?

Version 0.3.0 turns those questions into working features and tests.

What FreshCtx does

A FreshCtx workflow has three important moments:

  1. The application observes the evidence used by the agent.
  2. It declares which evidence the reasoning depends on.
  3. FreshCtx revalidates that evidence immediately before the protected action.
from freshctx import FreshnessBlocked, guard, observe, reasoning

try:
    with guard() as ctx:
        approval = observe("approval.json")

        with reasoning("release_payment", [approval]) as decision:
            payment = prepare_payment()

        ctx.run(
            send_payment,
            payment,
            depends_on=[decision],
        )

except FreshnessBlocked as blocked:
    print(blocked.result.state.value)
Enter fullscreen mode Exit fullscreen mode

If approval.json changes before send_payment runs, the action is blocked.

FreshCtx does not decide whether the payment is sensible. It checks whether the declared evidence behind that decision is still current.

Native async support

Agent services increasingly run inside asynchronous applications. FreshCtx 0.3.0 adds an async context manager, async validation and protected async actions.

async with guard() as ctx:
    approval = observe("approval.json")

    with reasoning("confirm_booking", [approval]) as decision:
        booking = prepare_booking()

    await ctx.run_async(
        confirm_booking,
        booking,
        depends_on=[decision],
    )
Enter fullscreen mode Exit fullscreen mode

Synchronous adapter validation is moved away from the event-loop thread. The same blocking, audit and fail-closed behavior still applies.

The original synchronous API remains unchanged.

Concurrent dependency validation

Checking dependencies one at a time can become expensive when an action depends on several independent sources.

FreshCtx now supports bounded concurrent validation:

with guard(
    validation_workers=8,
    validation_budget_ms=500,
) as ctx:
    result = ctx.check(decision)
Enter fullscreen mode Exit fullscreen mode

Concurrency is opt-in. The default remains one worker for compatibility.

An adapter must explicitly declare that it is thread-safe before FreshCtx runs it concurrently. Adapters that do not make that declaration remain sequential.

This matters because an application-supplied client, MCP session or transport may not be safe to call from multiple threads.

Validation budgets

A source may be slow, unavailable or rate-limited.

FreshCtx now supports a total decision-validity budget. If validation does not finish within that budget, unfinished evidence becomes UNVERIFIABLE.

It is not silently treated as current.

FreshCtx also records:

  • Per-dependency validation duration
  • Total validation duration
  • Worker count
  • Configured validation budget
  • Whether validation ran sequentially or concurrently

The budget is not unsafe thread cancellation. A validator that has already started is allowed to reach its adapter-specific timeout, but its late result is discarded. No validator is left running after the check returns.

A bounded performance result

We tested both wide and deep synthetic graphs containing 128 dependencies.

With eight validation workers, the observed p95 results were:

Graph Sequential p95 Concurrent p95
Wide 181 ms 29 ms
Deep 179 ms 29 ms

Both paths evaluated all 128 dependencies and returned CURRENT.

These numbers are an engineering baseline, not a production latency claim. Real performance will depend on source behavior, network latency, timeouts, adapter implementation and the structure of the protected workflow.

The benchmark is included so anyone can reproduce it or change the graph size:

python scripts/benchmark_validation.py \
  --width 128 \
  --workers 8 \
  --delay-ms 1 \
  --iterations 5
Enter fullscreen mode Exit fullscreen mode

Store migration and integrity checks

FreshCtx uses a local SQLite store by default.

Version 0.3.0 adds:

  • Transactional schema versioning
  • Forward migration of existing stores
  • Integrity checking
  • Rejection of unsupported future schemas
  • Clear corruption and migration errors

A store created by the original v0.1 API can be opened without rewriting its existing observation and reasoning objects.

If a store is damaged, FreshCtx does not guess or treat its contents as current.

New command-line tools

FreshCtx now installs a command-line interface.

Check the installation and local store:

freshctx doctor --store .freshctx/freshctx.db
Enter fullscreen mode Exit fullscreen mode

Check a stored subject:

freshctx check SUBJECT_ID \
  --store .freshctx/freshctx.db
Enter fullscreen mode Exit fullscreen mode

Summarize an audit trail:

freshctx audit \
  --audit .freshctx/audit.jsonl
Enter fullscreen mode Exit fullscreen mode

The commands operate locally. They do not require an account or upload evidence to a hosted service.

Adapter conformance now fails closed

FreshCtx adapters must return one of three results:

  • equivalent
  • changed
  • indeterminate

Version 0.3.0 adds a shared conformance layer.

If an adapter returns an invalid type or unsupported outcome, FreshCtx converts it to UNVERIFIABLE instead of accepting an ambiguous result.

This protects the enforcement boundary from an incorrectly implemented extension.

Recording independent results

The release also includes a portable validation-report schema.

An external test can now record:

  • The exact FreshCtx version
  • Whether installation came from PyPI, a wheel or source
  • The tested environment
  • Expected and observed behavior
  • Pass, fail or inconclusive verdict
  • Evidence locations
  • Limitations
  • Validator identity, when provided

This is deliberately a bounded result format.

A successful test of one scenario is evidence for that scenario. It is not automatically a security certification, production validation or proof that every agent integration is safe.

Release verification

FreshCtx 0.3.0 passed all of its defined release gates:

  • 68 automated tests
  • Python 3.10, 3.11, 3.12 and 3.13
  • Windows onboarding
  • Static analysis
  • Dependency audit
  • Package and metadata verification
  • Clean installation from public PyPI
  • Async, payment, booking, voice-agent and manual preflight scenarios
  • Wide and deep 128-dependency benchmarks

The public package was then installed into a brand-new environment and verified again.

Try it

pip install freshctx==0.3.0
freshctx demo
freshctx doctor
Enter fullscreen mode Exit fullscreen mode

PyPI:

https://pypi.org/project/freshctx/0.3.0/

GitHub:

https://github.com/Hyperwise-LLC/freshctx

Release notes:

https://github.com/Hyperwise-LLC/freshctx/releases/tag/v0.3.0

What comes next

This completes the current FreshCtx Core milestone.

We are testing the published package against real agent workflows involving mutable files, APIs, databases, approvals, bookings and MCP resources.

If you operate an agent that revalidates information before a write, I would be interested in one specific question:

Where do you currently place that boundary - inside every tool, inside the agent harness or in a separate control layer?

I am looking for developers willing to run one bounded scenario from a clean pip install freshctx==0.3.0 environment and publish the result either way.

Top comments (0)