Releases: fault-project/fault-cli
0.20.11
Changes
[0.20.11] - 2026-06-01
Fixed
- HTTP forward proxy: Host header now always set to upstream host —
previously the client's originalHostheader (pointing at the proxy
address, e.g.fault-proxy-myapi:3180) was forwarded verbatim to the
upstream server, which would reject the request with a400or a connection
reset. Firefox reports this asNS_ERROR_INTERCEPTION_FAILEDfor CORS
requests.curlusers working around it by passing-H "Host: real-host"
masked the bug. The proxy now always overwritesHostwith the upstream
hostname derived from the resolved URL, regardless of what the client sent.
Added
- Stream summary log in HTTP forward path — the
info!stream summary
line (src / dst / status / fault / bypassed) was previously only emitted
for TCP and HTTP CONNECT (tunnel) paths. It is now also emitted for plain
HTTP requests handled by the forward proxy, completing the logging story
for all three proxy paths.
[0.20.10] - 2026-06-01
Fixed
- HTTP proxy mode: faults were always bypassed — when no
--upstreamflag
is passed,upstream_hostsis empty, so every host fails the membership
check andpassthrough=true. No faults were ever applied. The injected
proxy Job now passes--upstream "*"in HTTP mode, which is the wildcard
meaning "fault all hosts". This is correct for the injected case since the
proxy only receives traffic already routed to it by the Service selector
patch.
[0.20.9] - 2026-06-01
Fixed
- HTTP proxy mode not reachable in Kubernetes — when
--with-http-response
was set, the injected proxy Job started the HTTP CONNECT proxy on
127.0.0.1:3180(the default). Inside a pod, Kubernetes Service traffic
arrives on the pod's non-loopback interface, so connections were silently
dropped. The HTTP mode args now pass--proxy-address 0.0.0.0:{proxy_port}
so the HTTP CONNECT proxy binds to all interfaces and is reachable from the
Service.
[0.20.8] - 2026-06-01
Changed
-
Stream summary log is now
infolevel with a readable one-liner —
previously a structuredtrace!event with key=value fields, now a plain
info!message in the format:src: 10.0.1.5:43210 dst: my-api-backend[10.0.2.3:5432] fault: latency(mean=200ms) bypassed: no src: 10.0.1.5:43211 dst: prod-db.example.com[10.0.2.4:5432] fault: none bypassed: noBoth hostname and resolved IP:port are shown in the
dstfield so you
don't need to memorise IP addresses. Emitted from both the TCP proxy
and HTTP CONNECT tunnel paths.
[0.20.7] - 2026-06-01
Added
-
--verboseflag forfault inject kubernetes— the injected proxy Job
now runs atinfolog level by default (previouslydebug). Pass
--verboseto getdebug-level logs from the proxy container, or set
FAULT_INJECTION_K8S_VERBOSE=true. -
Lean
trace-level stream summary log — after each stream completes, a
single structuredtraceevent is emitted with the following fields:src— client socket address (IP:port)dst— upstream socket address (IP:port)host— upstream hostname (HTTP CONNECT path only)bypassed— whether fault injection was skipped for this streamfault— comma-separated list of active fault injectors, or"none"c2s_bytes/s2c_bytes— bytes transferred in each direction
Emitted from both the TCP proxy path (
tcp/mod.rs) and the HTTP CONNECT
tunnel path (http/proxy/tunnel.rs). To see these lines set the proxy
log level totrace(e.g. viaFAULT_LOG_LEVEL=traceor
--log-level tracewhen runningfault runlocally).
[0.20.6] - 2026-06-01
Added
-
--dry-runforfault inject kubernetes— prints the full injection
plan without making any changes to the cluster.Inbound mode (
--service) shows: target service name/namespace, current
selector and ports, resources that would be created (ServiceAccount,
ConfigMap, Job, backend Service), and the Service patch that would be
applied.Standalone outbound mode (
--env-override) shows: proxy name/namespace/
upstream/listen port, resources that would be created, each env var key
with its resolved value ({host}and{port}substituted), and active
fault settings. -
Clear rollback failure output — if
plt.rollback()fails, a prominent
ERROR:message is printed to stderr with the error, the likely leftover
resources to clean up manually, and guidance on restoring the original
Service selector. The process exits with a non-zero status.
[0.20.5] - 2026-06-01
Fixed
- Ctrl-C now always triggers rollback — previously, when no
--duration
was set, the confirmation prompt (Press 'y' to finish and rollback) blocked
the async runtime synchronously. A SIGINT at that point killed the process
beforeplt.rollback()could run, leaving injected Service selectors and
proxy resources in place. The prompt is now run on a thread-pool thread via
spawn_blockingso the async runtime stays live; atokio::select!races
the prompt completion againstctrl_c(), and rollback always executes
afterward.
Added
- System service protection — the Kubernetes API server service
(kubernetesindefault) and all services in system namespaces
(kube-system,kube-public,kube-node-lease) are now excluded from the
interactive service selection list and blocked at theset_servicecall when
passed via--service. Attempting to inject into a protected service returns
a clear error message suggesting--nsif the wrong namespace was used.
[0.20.4] - 2026-06-01
Changed
-
fault inject kubernetes: HTTP error fault now forces HTTP proxy mode —
when--with-http-responseis set, the injected proxy Job runs as an HTTP
CONNECT proxy (omitting--disable-http-proxyand--proxy). This is the
only mode that can inspect and rewrite HTTP responses at L7. All other faults
continue to use TCP proxy mode (transparent, L4 only). -
--with-http-responsehelp text clarifies that HTTP error injection
requires inbound proxy mode (--service). Standalone outbound mode
(--env-overridewithout--service) cannot use HTTP error faults because
the TCP proxy has no L7 visibility.
[0.20.3] - 2026-06-01
Fixed
--env-overrideupstream resolution with split host/port keys — when
separateDB_HOST={host}andDB_PORT={port}overrides are used, the proxy
upstream was assembled from only the first key's current value, producing a
portless address (e.g.prod-db.example.cominstead of
prod-db.example.com:5432) which caused the proxy to fail to connect.
resolve_upstreamnow reads both keys and combines them intohost:port.
[0.20.2] - 2026-06-01
Changed
-
--env-overridetemplate substitution — the value now supports
{host}and{port}placeholders that fault replaces with the proxy's
in-cluster name and port (3180) at inject time. Any combination works:--env-override configmap/my-config:DB_HOST={host} --env-override configmap/my-config:DB_PORT={port} --env-override configmap/my-config:DATABASE_URL=postgres://{host}:{port}/mydb --env-override configmap/my-config:API_URL=https://{host}:{port}/v1Values without
{host}or{port}are treated as literals (unchanged
from before).
Removed
- Bare
KEYwithout=VALUE— previously accepted as an auto-inject
shorthand, now a parse error. UseKEY={host}:{port}instead.
[0.20.1] - 2026-06-01
Changed
-
--env-overrideauto proxy address injection — the value side is now
optional.kind/name:KEY(no=VALUE) instructs fault to automatically
fill in the proxy's own in-cluster address (proxy-name:3180) at inject
time, so you no longer need to know the proxy name ahead of time when using
a generated suffix. -
--env-overridevalue is nowExplicit | Auto— internally the value
field is now a typed enum; the parser accepts bothKEY=VALUEand bare
KEY.
Removed
-
--env-override-ns— dropped before it shipped. The--nsflag already
scopes everything; a separate override namespace would require cross-namespace
RBAC which is out of scope. -
Port derivation from
--env-overridevalue — the standalone proxy
always listens on port3180, consistent with the inbound proxy. The
:PORTsuffix in an explicit value is the upstream port, not the proxy's
listen port; parsing it as the proxy port was wrong.
[0.20.0] - 2026-05-29
Added
-
Kubernetes injection: outbound (standalone) proxy mode — inject faults on
traffic a pod sends to a downstream dependency (e.g. a cloud DB), not just
on inbound traffic arriving at the pod.Triggered by passing one or more
--env-overrideflags without--service.
A standalone fault proxy Job + ClusterIP Service is created; env vars in the
named ConfigMaps, Deployments, or StatefulSets are patched to redirect the
downstream address through the proxy. On rollback, original values are
restored and the proxy resources are deleted.fault inject kubernetes \ --env-override configmap/my-app-config:DB_HOST=fault-proxy-db:5432 \ --with-latency --latency-mean 200 -
--env-override kind/name:KEY=VALUE— new repeatable flag for the
Kubernetes injector. Patches a specific key in a ConfigMap, Deployment, or
StatefulSet (aliases:cm,deploy,sts). For Deployment/StatefulSet a
rolling restart annotation is added; for ConfigMap only the data key is
patched (rollout is left to the operator). Original values are stored in the
rollback snapshot and restored automatically. -
--name— optional name for the standalone proxy resources. When omitted
a short random suffix is generated (fault-proxy-<6 chars>). Useful in
scripts where the proxy address must be known ahead of time and embedded in
the `--en...
0.20.10
Changes
[0.20.10] - 2026-06-01
Fixed
- HTTP proxy mode: faults were always bypassed — when no
--upstreamflag
is passed,upstream_hostsis empty, so every host fails the membership
check andpassthrough=true. No faults were ever applied. The injected
proxy Job now passes--upstream "*"in HTTP mode, which is the wildcard
meaning "fault all hosts". This is correct for the injected case since the
proxy only receives traffic already routed to it by the Service selector
patch.
[0.20.9] - 2026-06-01
Fixed
- HTTP proxy mode not reachable in Kubernetes — when
--with-http-response
was set, the injected proxy Job started the HTTP CONNECT proxy on
127.0.0.1:3180(the default). Inside a pod, Kubernetes Service traffic
arrives on the pod's non-loopback interface, so connections were silently
dropped. The HTTP mode args now pass--proxy-address 0.0.0.0:{proxy_port}
so the HTTP CONNECT proxy binds to all interfaces and is reachable from the
Service.
[0.20.8] - 2026-06-01
Changed
-
Stream summary log is now
infolevel with a readable one-liner —
previously a structuredtrace!event with key=value fields, now a plain
info!message in the format:src: 10.0.1.5:43210 dst: my-api-backend[10.0.2.3:5432] fault: latency(mean=200ms) bypassed: no src: 10.0.1.5:43211 dst: prod-db.example.com[10.0.2.4:5432] fault: none bypassed: noBoth hostname and resolved IP:port are shown in the
dstfield so you
don't need to memorise IP addresses. Emitted from both the TCP proxy
and HTTP CONNECT tunnel paths.
[0.20.7] - 2026-06-01
Added
-
--verboseflag forfault inject kubernetes— the injected proxy Job
now runs atinfolog level by default (previouslydebug). Pass
--verboseto getdebug-level logs from the proxy container, or set
FAULT_INJECTION_K8S_VERBOSE=true. -
Lean
trace-level stream summary log — after each stream completes, a
single structuredtraceevent is emitted with the following fields:src— client socket address (IP:port)dst— upstream socket address (IP:port)host— upstream hostname (HTTP CONNECT path only)bypassed— whether fault injection was skipped for this streamfault— comma-separated list of active fault injectors, or"none"c2s_bytes/s2c_bytes— bytes transferred in each direction
Emitted from both the TCP proxy path (
tcp/mod.rs) and the HTTP CONNECT
tunnel path (http/proxy/tunnel.rs). To see these lines set the proxy
log level totrace(e.g. viaFAULT_LOG_LEVEL=traceor
--log-level tracewhen runningfault runlocally).
[0.20.6] - 2026-06-01
Added
-
--dry-runforfault inject kubernetes— prints the full injection
plan without making any changes to the cluster.Inbound mode (
--service) shows: target service name/namespace, current
selector and ports, resources that would be created (ServiceAccount,
ConfigMap, Job, backend Service), and the Service patch that would be
applied.Standalone outbound mode (
--env-override) shows: proxy name/namespace/
upstream/listen port, resources that would be created, each env var key
with its resolved value ({host}and{port}substituted), and active
fault settings. -
Clear rollback failure output — if
plt.rollback()fails, a prominent
ERROR:message is printed to stderr with the error, the likely leftover
resources to clean up manually, and guidance on restoring the original
Service selector. The process exits with a non-zero status.
[0.20.5] - 2026-06-01
Fixed
- Ctrl-C now always triggers rollback — previously, when no
--duration
was set, the confirmation prompt (Press 'y' to finish and rollback) blocked
the async runtime synchronously. A SIGINT at that point killed the process
beforeplt.rollback()could run, leaving injected Service selectors and
proxy resources in place. The prompt is now run on a thread-pool thread via
spawn_blockingso the async runtime stays live; atokio::select!races
the prompt completion againstctrl_c(), and rollback always executes
afterward.
Added
- System service protection — the Kubernetes API server service
(kubernetesindefault) and all services in system namespaces
(kube-system,kube-public,kube-node-lease) are now excluded from the
interactive service selection list and blocked at theset_servicecall when
passed via--service. Attempting to inject into a protected service returns
a clear error message suggesting--nsif the wrong namespace was used.
[0.20.4] - 2026-06-01
Changed
-
fault inject kubernetes: HTTP error fault now forces HTTP proxy mode —
when--with-http-responseis set, the injected proxy Job runs as an HTTP
CONNECT proxy (omitting--disable-http-proxyand--proxy). This is the
only mode that can inspect and rewrite HTTP responses at L7. All other faults
continue to use TCP proxy mode (transparent, L4 only). -
--with-http-responsehelp text clarifies that HTTP error injection
requires inbound proxy mode (--service). Standalone outbound mode
(--env-overridewithout--service) cannot use HTTP error faults because
the TCP proxy has no L7 visibility.
[0.20.3] - 2026-06-01
Fixed
--env-overrideupstream resolution with split host/port keys — when
separateDB_HOST={host}andDB_PORT={port}overrides are used, the proxy
upstream was assembled from only the first key's current value, producing a
portless address (e.g.prod-db.example.cominstead of
prod-db.example.com:5432) which caused the proxy to fail to connect.
resolve_upstreamnow reads both keys and combines them intohost:port.
[0.20.2] - 2026-06-01
Changed
-
--env-overridetemplate substitution — the value now supports
{host}and{port}placeholders that fault replaces with the proxy's
in-cluster name and port (3180) at inject time. Any combination works:--env-override configmap/my-config:DB_HOST={host} --env-override configmap/my-config:DB_PORT={port} --env-override configmap/my-config:DATABASE_URL=postgres://{host}:{port}/mydb --env-override configmap/my-config:API_URL=https://{host}:{port}/v1Values without
{host}or{port}are treated as literals (unchanged
from before).
Removed
- Bare
KEYwithout=VALUE— previously accepted as an auto-inject
shorthand, now a parse error. UseKEY={host}:{port}instead.
[0.20.1] - 2026-06-01
Changed
-
--env-overrideauto proxy address injection — the value side is now
optional.kind/name:KEY(no=VALUE) instructs fault to automatically
fill in the proxy's own in-cluster address (proxy-name:3180) at inject
time, so you no longer need to know the proxy name ahead of time when using
a generated suffix. -
--env-overridevalue is nowExplicit | Auto— internally the value
field is now a typed enum; the parser accepts bothKEY=VALUEand bare
KEY.
Removed
-
--env-override-ns— dropped before it shipped. The--nsflag already
scopes everything; a separate override namespace would require cross-namespace
RBAC which is out of scope. -
Port derivation from
--env-overridevalue — the standalone proxy
always listens on port3180, consistent with the inbound proxy. The
:PORTsuffix in an explicit value is the upstream port, not the proxy's
listen port; parsing it as the proxy port was wrong.
[0.20.0] - 2026-05-29
Added
-
Kubernetes injection: outbound (standalone) proxy mode — inject faults on
traffic a pod sends to a downstream dependency (e.g. a cloud DB), not just
on inbound traffic arriving at the pod.Triggered by passing one or more
--env-overrideflags without--service.
A standalone fault proxy Job + ClusterIP Service is created; env vars in the
named ConfigMaps, Deployments, or StatefulSets are patched to redirect the
downstream address through the proxy. On rollback, original values are
restored and the proxy resources are deleted.fault inject kubernetes \ --env-override configmap/my-app-config:DB_HOST=fault-proxy-db:5432 \ --with-latency --latency-mean 200 -
--env-override kind/name:KEY=VALUE— new repeatable flag for the
Kubernetes injector. Patches a specific key in a ConfigMap, Deployment, or
StatefulSet (aliases:cm,deploy,sts). For Deployment/StatefulSet a
rolling restart annotation is added; for ConfigMap only the data key is
patched (rollout is left to the operator). Original values are stored in the
rollback snapshot and restored automatically. -
--name— optional name for the standalone proxy resources. When omitted
a short random suffix is generated (fault-proxy-<6 chars>). Useful in
scripts where the proxy address must be known ahead of time and embedded in
the--env-overridevalue.
Fixed
BandwidthUnit::from_str: match arms used mixed case ("Bps","KBps")
after.to_lowercase(), making them unreachable. Arms are now all lowercase.
[0.19.1] - 2026-05-29
Fixed
- Kubernetes injection: handle named target ports in Service resources —
targetPortcan be a string (e.g."http") not only a number. Both
inject::k8s::runandinject::k8s::scenarionow fall back to
IntOrString::Stringwhen the numeric parse fails, instead of panicking on
unwrap().
[0.19.0] - 2026-05-28
Changed
- Agent vector database: replaced Qdrant (external server) with embedded LanceDB
- Removed
qdrant-clientcrate dependency; no Docker or network server needed - LanceDB stores data locally in
.fault/lancedb— tables created implicitly on first write - Sparse vector generation removed from retrieval (LanceDB uses Tantivy for FTS)
- Removed
create_index_if_not_exists()calls from all query pi...
- Removed
0.20.9
Changes
[0.20.9] - 2026-06-01
Fixed
- HTTP proxy mode not reachable in Kubernetes — when
--with-http-response
was set, the injected proxy Job started the HTTP CONNECT proxy on
127.0.0.1:3180(the default). Inside a pod, Kubernetes Service traffic
arrives on the pod's non-loopback interface, so connections were silently
dropped. The HTTP mode args now pass--proxy-address 0.0.0.0:{proxy_port}
so the HTTP CONNECT proxy binds to all interfaces and is reachable from the
Service.
[0.20.8] - 2026-06-01
Changed
-
Stream summary log is now
infolevel with a readable one-liner —
previously a structuredtrace!event with key=value fields, now a plain
info!message in the format:src: 10.0.1.5:43210 dst: my-api-backend[10.0.2.3:5432] fault: latency(mean=200ms) bypassed: no src: 10.0.1.5:43211 dst: prod-db.example.com[10.0.2.4:5432] fault: none bypassed: noBoth hostname and resolved IP:port are shown in the
dstfield so you
don't need to memorise IP addresses. Emitted from both the TCP proxy
and HTTP CONNECT tunnel paths.
[0.20.7] - 2026-06-01
Added
-
--verboseflag forfault inject kubernetes— the injected proxy Job
now runs atinfolog level by default (previouslydebug). Pass
--verboseto getdebug-level logs from the proxy container, or set
FAULT_INJECTION_K8S_VERBOSE=true. -
Lean
trace-level stream summary log — after each stream completes, a
single structuredtraceevent is emitted with the following fields:src— client socket address (IP:port)dst— upstream socket address (IP:port)host— upstream hostname (HTTP CONNECT path only)bypassed— whether fault injection was skipped for this streamfault— comma-separated list of active fault injectors, or"none"c2s_bytes/s2c_bytes— bytes transferred in each direction
Emitted from both the TCP proxy path (
tcp/mod.rs) and the HTTP CONNECT
tunnel path (http/proxy/tunnel.rs). To see these lines set the proxy
log level totrace(e.g. viaFAULT_LOG_LEVEL=traceor
--log-level tracewhen runningfault runlocally).
[0.20.6] - 2026-06-01
Added
-
--dry-runforfault inject kubernetes— prints the full injection
plan without making any changes to the cluster.Inbound mode (
--service) shows: target service name/namespace, current
selector and ports, resources that would be created (ServiceAccount,
ConfigMap, Job, backend Service), and the Service patch that would be
applied.Standalone outbound mode (
--env-override) shows: proxy name/namespace/
upstream/listen port, resources that would be created, each env var key
with its resolved value ({host}and{port}substituted), and active
fault settings. -
Clear rollback failure output — if
plt.rollback()fails, a prominent
ERROR:message is printed to stderr with the error, the likely leftover
resources to clean up manually, and guidance on restoring the original
Service selector. The process exits with a non-zero status.
[0.20.5] - 2026-06-01
Fixed
- Ctrl-C now always triggers rollback — previously, when no
--duration
was set, the confirmation prompt (Press 'y' to finish and rollback) blocked
the async runtime synchronously. A SIGINT at that point killed the process
beforeplt.rollback()could run, leaving injected Service selectors and
proxy resources in place. The prompt is now run on a thread-pool thread via
spawn_blockingso the async runtime stays live; atokio::select!races
the prompt completion againstctrl_c(), and rollback always executes
afterward.
Added
- System service protection — the Kubernetes API server service
(kubernetesindefault) and all services in system namespaces
(kube-system,kube-public,kube-node-lease) are now excluded from the
interactive service selection list and blocked at theset_servicecall when
passed via--service. Attempting to inject into a protected service returns
a clear error message suggesting--nsif the wrong namespace was used.
[0.20.4] - 2026-06-01
Changed
-
fault inject kubernetes: HTTP error fault now forces HTTP proxy mode —
when--with-http-responseis set, the injected proxy Job runs as an HTTP
CONNECT proxy (omitting--disable-http-proxyand--proxy). This is the
only mode that can inspect and rewrite HTTP responses at L7. All other faults
continue to use TCP proxy mode (transparent, L4 only). -
--with-http-responsehelp text clarifies that HTTP error injection
requires inbound proxy mode (--service). Standalone outbound mode
(--env-overridewithout--service) cannot use HTTP error faults because
the TCP proxy has no L7 visibility.
[0.20.3] - 2026-06-01
Fixed
--env-overrideupstream resolution with split host/port keys — when
separateDB_HOST={host}andDB_PORT={port}overrides are used, the proxy
upstream was assembled from only the first key's current value, producing a
portless address (e.g.prod-db.example.cominstead of
prod-db.example.com:5432) which caused the proxy to fail to connect.
resolve_upstreamnow reads both keys and combines them intohost:port.
[0.20.2] - 2026-06-01
Changed
-
--env-overridetemplate substitution — the value now supports
{host}and{port}placeholders that fault replaces with the proxy's
in-cluster name and port (3180) at inject time. Any combination works:--env-override configmap/my-config:DB_HOST={host} --env-override configmap/my-config:DB_PORT={port} --env-override configmap/my-config:DATABASE_URL=postgres://{host}:{port}/mydb --env-override configmap/my-config:API_URL=https://{host}:{port}/v1Values without
{host}or{port}are treated as literals (unchanged
from before).
Removed
- Bare
KEYwithout=VALUE— previously accepted as an auto-inject
shorthand, now a parse error. UseKEY={host}:{port}instead.
[0.20.1] - 2026-06-01
Changed
-
--env-overrideauto proxy address injection — the value side is now
optional.kind/name:KEY(no=VALUE) instructs fault to automatically
fill in the proxy's own in-cluster address (proxy-name:3180) at inject
time, so you no longer need to know the proxy name ahead of time when using
a generated suffix. -
--env-overridevalue is nowExplicit | Auto— internally the value
field is now a typed enum; the parser accepts bothKEY=VALUEand bare
KEY.
Removed
-
--env-override-ns— dropped before it shipped. The--nsflag already
scopes everything; a separate override namespace would require cross-namespace
RBAC which is out of scope. -
Port derivation from
--env-overridevalue — the standalone proxy
always listens on port3180, consistent with the inbound proxy. The
:PORTsuffix in an explicit value is the upstream port, not the proxy's
listen port; parsing it as the proxy port was wrong.
[0.20.0] - 2026-05-29
Added
-
Kubernetes injection: outbound (standalone) proxy mode — inject faults on
traffic a pod sends to a downstream dependency (e.g. a cloud DB), not just
on inbound traffic arriving at the pod.Triggered by passing one or more
--env-overrideflags without--service.
A standalone fault proxy Job + ClusterIP Service is created; env vars in the
named ConfigMaps, Deployments, or StatefulSets are patched to redirect the
downstream address through the proxy. On rollback, original values are
restored and the proxy resources are deleted.fault inject kubernetes \ --env-override configmap/my-app-config:DB_HOST=fault-proxy-db:5432 \ --with-latency --latency-mean 200 -
--env-override kind/name:KEY=VALUE— new repeatable flag for the
Kubernetes injector. Patches a specific key in a ConfigMap, Deployment, or
StatefulSet (aliases:cm,deploy,sts). For Deployment/StatefulSet a
rolling restart annotation is added; for ConfigMap only the data key is
patched (rollout is left to the operator). Original values are stored in the
rollback snapshot and restored automatically. -
--name— optional name for the standalone proxy resources. When omitted
a short random suffix is generated (fault-proxy-<6 chars>). Useful in
scripts where the proxy address must be known ahead of time and embedded in
the--env-overridevalue.
Fixed
BandwidthUnit::from_str: match arms used mixed case ("Bps","KBps")
after.to_lowercase(), making them unreachable. Arms are now all lowercase.
[0.19.1] - 2026-05-29
Fixed
- Kubernetes injection: handle named target ports in Service resources —
targetPortcan be a string (e.g."http") not only a number. Both
inject::k8s::runandinject::k8s::scenarionow fall back to
IntOrString::Stringwhen the numeric parse fails, instead of panicking on
unwrap().
[0.19.0] - 2026-05-28
Changed
- Agent vector database: replaced Qdrant (external server) with embedded LanceDB
- Removed
qdrant-clientcrate dependency; no Docker or network server needed - LanceDB stores data locally in
.fault/lancedb— tables created implicitly on first write - Sparse vector generation removed from retrieval (LanceDB uses Tantivy for FTS)
- Removed
create_index_if_not_exists()calls from all query pipelines - All batch sizes updated to
usizeliterals to match LanceDB builder API - Custom
OpIdRetrieverstruct insuggestion.rsreplaced withSimilaritySingleEmbedding<String>using LanceDB native filter syntax (operation_id = '{opid}') HybridSearch<Filter>replaced withSimilaritySingleEmbedding<String>across all query pipelines- All Qdrant builder calls replaced with LanceDB equivalents (
.uri(),.table_name())
- Removed
[0.18.0] - 2026-05-28
Added
- Agent: Anthropic/C...
0.20.8
Changes
[0.20.8] - 2026-06-01
Changed
-
Stream summary log is now
infolevel with a readable one-liner —
previously a structuredtrace!event with key=value fields, now a plain
info!message in the format:src: 10.0.1.5:43210 dst: my-api-backend[10.0.2.3:5432] fault: latency(mean=200ms) bypassed: no src: 10.0.1.5:43211 dst: prod-db.example.com[10.0.2.4:5432] fault: none bypassed: noBoth hostname and resolved IP:port are shown in the
dstfield so you
don't need to memorise IP addresses. Emitted from both the TCP proxy
and HTTP CONNECT tunnel paths.
[0.20.7] - 2026-06-01
Added
-
--verboseflag forfault inject kubernetes— the injected proxy Job
now runs atinfolog level by default (previouslydebug). Pass
--verboseto getdebug-level logs from the proxy container, or set
FAULT_INJECTION_K8S_VERBOSE=true. -
Lean
trace-level stream summary log — after each stream completes, a
single structuredtraceevent is emitted with the following fields:src— client socket address (IP:port)dst— upstream socket address (IP:port)host— upstream hostname (HTTP CONNECT path only)bypassed— whether fault injection was skipped for this streamfault— comma-separated list of active fault injectors, or"none"c2s_bytes/s2c_bytes— bytes transferred in each direction
Emitted from both the TCP proxy path (
tcp/mod.rs) and the HTTP CONNECT
tunnel path (http/proxy/tunnel.rs). To see these lines set the proxy
log level totrace(e.g. viaFAULT_LOG_LEVEL=traceor
--log-level tracewhen runningfault runlocally).
[0.20.6] - 2026-06-01
Added
-
--dry-runforfault inject kubernetes— prints the full injection
plan without making any changes to the cluster.Inbound mode (
--service) shows: target service name/namespace, current
selector and ports, resources that would be created (ServiceAccount,
ConfigMap, Job, backend Service), and the Service patch that would be
applied.Standalone outbound mode (
--env-override) shows: proxy name/namespace/
upstream/listen port, resources that would be created, each env var key
with its resolved value ({host}and{port}substituted), and active
fault settings. -
Clear rollback failure output — if
plt.rollback()fails, a prominent
ERROR:message is printed to stderr with the error, the likely leftover
resources to clean up manually, and guidance on restoring the original
Service selector. The process exits with a non-zero status.
[0.20.5] - 2026-06-01
Fixed
- Ctrl-C now always triggers rollback — previously, when no
--duration
was set, the confirmation prompt (Press 'y' to finish and rollback) blocked
the async runtime synchronously. A SIGINT at that point killed the process
beforeplt.rollback()could run, leaving injected Service selectors and
proxy resources in place. The prompt is now run on a thread-pool thread via
spawn_blockingso the async runtime stays live; atokio::select!races
the prompt completion againstctrl_c(), and rollback always executes
afterward.
Added
- System service protection — the Kubernetes API server service
(kubernetesindefault) and all services in system namespaces
(kube-system,kube-public,kube-node-lease) are now excluded from the
interactive service selection list and blocked at theset_servicecall when
passed via--service. Attempting to inject into a protected service returns
a clear error message suggesting--nsif the wrong namespace was used.
[0.20.4] - 2026-06-01
Changed
-
fault inject kubernetes: HTTP error fault now forces HTTP proxy mode —
when--with-http-responseis set, the injected proxy Job runs as an HTTP
CONNECT proxy (omitting--disable-http-proxyand--proxy). This is the
only mode that can inspect and rewrite HTTP responses at L7. All other faults
continue to use TCP proxy mode (transparent, L4 only). -
--with-http-responsehelp text clarifies that HTTP error injection
requires inbound proxy mode (--service). Standalone outbound mode
(--env-overridewithout--service) cannot use HTTP error faults because
the TCP proxy has no L7 visibility.
[0.20.3] - 2026-06-01
Fixed
--env-overrideupstream resolution with split host/port keys — when
separateDB_HOST={host}andDB_PORT={port}overrides are used, the proxy
upstream was assembled from only the first key's current value, producing a
portless address (e.g.prod-db.example.cominstead of
prod-db.example.com:5432) which caused the proxy to fail to connect.
resolve_upstreamnow reads both keys and combines them intohost:port.
[0.20.2] - 2026-06-01
Changed
-
--env-overridetemplate substitution — the value now supports
{host}and{port}placeholders that fault replaces with the proxy's
in-cluster name and port (3180) at inject time. Any combination works:--env-override configmap/my-config:DB_HOST={host} --env-override configmap/my-config:DB_PORT={port} --env-override configmap/my-config:DATABASE_URL=postgres://{host}:{port}/mydb --env-override configmap/my-config:API_URL=https://{host}:{port}/v1Values without
{host}or{port}are treated as literals (unchanged
from before).
Removed
- Bare
KEYwithout=VALUE— previously accepted as an auto-inject
shorthand, now a parse error. UseKEY={host}:{port}instead.
[0.20.1] - 2026-06-01
Changed
-
--env-overrideauto proxy address injection — the value side is now
optional.kind/name:KEY(no=VALUE) instructs fault to automatically
fill in the proxy's own in-cluster address (proxy-name:3180) at inject
time, so you no longer need to know the proxy name ahead of time when using
a generated suffix. -
--env-overridevalue is nowExplicit | Auto— internally the value
field is now a typed enum; the parser accepts bothKEY=VALUEand bare
KEY.
Removed
-
--env-override-ns— dropped before it shipped. The--nsflag already
scopes everything; a separate override namespace would require cross-namespace
RBAC which is out of scope. -
Port derivation from
--env-overridevalue — the standalone proxy
always listens on port3180, consistent with the inbound proxy. The
:PORTsuffix in an explicit value is the upstream port, not the proxy's
listen port; parsing it as the proxy port was wrong.
[0.20.0] - 2026-05-29
Added
-
Kubernetes injection: outbound (standalone) proxy mode — inject faults on
traffic a pod sends to a downstream dependency (e.g. a cloud DB), not just
on inbound traffic arriving at the pod.Triggered by passing one or more
--env-overrideflags without--service.
A standalone fault proxy Job + ClusterIP Service is created; env vars in the
named ConfigMaps, Deployments, or StatefulSets are patched to redirect the
downstream address through the proxy. On rollback, original values are
restored and the proxy resources are deleted.fault inject kubernetes \ --env-override configmap/my-app-config:DB_HOST=fault-proxy-db:5432 \ --with-latency --latency-mean 200 -
--env-override kind/name:KEY=VALUE— new repeatable flag for the
Kubernetes injector. Patches a specific key in a ConfigMap, Deployment, or
StatefulSet (aliases:cm,deploy,sts). For Deployment/StatefulSet a
rolling restart annotation is added; for ConfigMap only the data key is
patched (rollout is left to the operator). Original values are stored in the
rollback snapshot and restored automatically. -
--name— optional name for the standalone proxy resources. When omitted
a short random suffix is generated (fault-proxy-<6 chars>). Useful in
scripts where the proxy address must be known ahead of time and embedded in
the--env-overridevalue.
Fixed
BandwidthUnit::from_str: match arms used mixed case ("Bps","KBps")
after.to_lowercase(), making them unreachable. Arms are now all lowercase.
[0.19.1] - 2026-05-29
Fixed
- Kubernetes injection: handle named target ports in Service resources —
targetPortcan be a string (e.g."http") not only a number. Both
inject::k8s::runandinject::k8s::scenarionow fall back to
IntOrString::Stringwhen the numeric parse fails, instead of panicking on
unwrap().
[0.19.0] - 2026-05-28
Changed
- Agent vector database: replaced Qdrant (external server) with embedded LanceDB
- Removed
qdrant-clientcrate dependency; no Docker or network server needed - LanceDB stores data locally in
.fault/lancedb— tables created implicitly on first write - Sparse vector generation removed from retrieval (LanceDB uses Tantivy for FTS)
- Removed
create_index_if_not_exists()calls from all query pipelines - All batch sizes updated to
usizeliterals to match LanceDB builder API - Custom
OpIdRetrieverstruct insuggestion.rsreplaced withSimilaritySingleEmbedding<String>using LanceDB native filter syntax (operation_id = '{opid}') HybridSearch<Filter>replaced withSimilaritySingleEmbedding<String>across all query pipelines- All Qdrant builder calls replaced with LanceDB equivalents (
.uri(),.table_name())
- Removed
[0.18.0] - 2026-05-28
Added
- Agent: Anthropic/Claude LLM client support —
--llm-client claude(alias:claude,anthropic)- Uses Claude's native Messages API via the
async-anthropiccrate - Reads
ANTHROPIC_API_KEYfrom the environment - Embedding support via local FastEmbed (Anthropic doesn't provide native embeddings)
- Uses Claude's native Messages API via the
[0.17.1] - 2026-02-27
Fixed
- ci: set
aarch64-linux-gnu-gccas linker foraarch64-unknown-linux-gnucross-compilation to fix x86_64/aarch64 ELF incompatibility error
[0.17.0] - 2026-02-27
Added
...
0.20.7
Changes
[0.20.7] - 2026-06-01
Added
-
--verboseflag forfault inject kubernetes— the injected proxy Job
now runs atinfolog level by default (previouslydebug). Pass
--verboseto getdebug-level logs from the proxy container, or set
FAULT_INJECTION_K8S_VERBOSE=true. -
Lean
trace-level stream summary log — after each stream completes, a
single structuredtraceevent is emitted with the following fields:src— client socket address (IP:port)dst— upstream socket address (IP:port)host— upstream hostname (HTTP CONNECT path only)bypassed— whether fault injection was skipped for this streamfault— comma-separated list of active fault injectors, or"none"c2s_bytes/s2c_bytes— bytes transferred in each direction
Emitted from both the TCP proxy path (
tcp/mod.rs) and the HTTP CONNECT
tunnel path (http/proxy/tunnel.rs). To see these lines set the proxy
log level totrace(e.g. viaFAULT_LOG_LEVEL=traceor
--log-level tracewhen runningfault runlocally).
[0.20.6] - 2026-06-01
Added
-
--dry-runforfault inject kubernetes— prints the full injection
plan without making any changes to the cluster.Inbound mode (
--service) shows: target service name/namespace, current
selector and ports, resources that would be created (ServiceAccount,
ConfigMap, Job, backend Service), and the Service patch that would be
applied.Standalone outbound mode (
--env-override) shows: proxy name/namespace/
upstream/listen port, resources that would be created, each env var key
with its resolved value ({host}and{port}substituted), and active
fault settings. -
Clear rollback failure output — if
plt.rollback()fails, a prominent
ERROR:message is printed to stderr with the error, the likely leftover
resources to clean up manually, and guidance on restoring the original
Service selector. The process exits with a non-zero status.
[0.20.5] - 2026-06-01
Fixed
- Ctrl-C now always triggers rollback — previously, when no
--duration
was set, the confirmation prompt (Press 'y' to finish and rollback) blocked
the async runtime synchronously. A SIGINT at that point killed the process
beforeplt.rollback()could run, leaving injected Service selectors and
proxy resources in place. The prompt is now run on a thread-pool thread via
spawn_blockingso the async runtime stays live; atokio::select!races
the prompt completion againstctrl_c(), and rollback always executes
afterward.
Added
- System service protection — the Kubernetes API server service
(kubernetesindefault) and all services in system namespaces
(kube-system,kube-public,kube-node-lease) are now excluded from the
interactive service selection list and blocked at theset_servicecall when
passed via--service. Attempting to inject into a protected service returns
a clear error message suggesting--nsif the wrong namespace was used.
[0.20.4] - 2026-06-01
Changed
-
fault inject kubernetes: HTTP error fault now forces HTTP proxy mode —
when--with-http-responseis set, the injected proxy Job runs as an HTTP
CONNECT proxy (omitting--disable-http-proxyand--proxy). This is the
only mode that can inspect and rewrite HTTP responses at L7. All other faults
continue to use TCP proxy mode (transparent, L4 only). -
--with-http-responsehelp text clarifies that HTTP error injection
requires inbound proxy mode (--service). Standalone outbound mode
(--env-overridewithout--service) cannot use HTTP error faults because
the TCP proxy has no L7 visibility.
[0.20.3] - 2026-06-01
Fixed
--env-overrideupstream resolution with split host/port keys — when
separateDB_HOST={host}andDB_PORT={port}overrides are used, the proxy
upstream was assembled from only the first key's current value, producing a
portless address (e.g.prod-db.example.cominstead of
prod-db.example.com:5432) which caused the proxy to fail to connect.
resolve_upstreamnow reads both keys and combines them intohost:port.
[0.20.2] - 2026-06-01
Changed
-
--env-overridetemplate substitution — the value now supports
{host}and{port}placeholders that fault replaces with the proxy's
in-cluster name and port (3180) at inject time. Any combination works:--env-override configmap/my-config:DB_HOST={host} --env-override configmap/my-config:DB_PORT={port} --env-override configmap/my-config:DATABASE_URL=postgres://{host}:{port}/mydb --env-override configmap/my-config:API_URL=https://{host}:{port}/v1Values without
{host}or{port}are treated as literals (unchanged
from before).
Removed
- Bare
KEYwithout=VALUE— previously accepted as an auto-inject
shorthand, now a parse error. UseKEY={host}:{port}instead.
[0.20.1] - 2026-06-01
Changed
-
--env-overrideauto proxy address injection — the value side is now
optional.kind/name:KEY(no=VALUE) instructs fault to automatically
fill in the proxy's own in-cluster address (proxy-name:3180) at inject
time, so you no longer need to know the proxy name ahead of time when using
a generated suffix. -
--env-overridevalue is nowExplicit | Auto— internally the value
field is now a typed enum; the parser accepts bothKEY=VALUEand bare
KEY.
Removed
-
--env-override-ns— dropped before it shipped. The--nsflag already
scopes everything; a separate override namespace would require cross-namespace
RBAC which is out of scope. -
Port derivation from
--env-overridevalue — the standalone proxy
always listens on port3180, consistent with the inbound proxy. The
:PORTsuffix in an explicit value is the upstream port, not the proxy's
listen port; parsing it as the proxy port was wrong.
[0.20.0] - 2026-05-29
Added
-
Kubernetes injection: outbound (standalone) proxy mode — inject faults on
traffic a pod sends to a downstream dependency (e.g. a cloud DB), not just
on inbound traffic arriving at the pod.Triggered by passing one or more
--env-overrideflags without--service.
A standalone fault proxy Job + ClusterIP Service is created; env vars in the
named ConfigMaps, Deployments, or StatefulSets are patched to redirect the
downstream address through the proxy. On rollback, original values are
restored and the proxy resources are deleted.fault inject kubernetes \ --env-override configmap/my-app-config:DB_HOST=fault-proxy-db:5432 \ --with-latency --latency-mean 200 -
--env-override kind/name:KEY=VALUE— new repeatable flag for the
Kubernetes injector. Patches a specific key in a ConfigMap, Deployment, or
StatefulSet (aliases:cm,deploy,sts). For Deployment/StatefulSet a
rolling restart annotation is added; for ConfigMap only the data key is
patched (rollout is left to the operator). Original values are stored in the
rollback snapshot and restored automatically. -
--name— optional name for the standalone proxy resources. When omitted
a short random suffix is generated (fault-proxy-<6 chars>). Useful in
scripts where the proxy address must be known ahead of time and embedded in
the--env-overridevalue.
Fixed
BandwidthUnit::from_str: match arms used mixed case ("Bps","KBps")
after.to_lowercase(), making them unreachable. Arms are now all lowercase.
[0.19.1] - 2026-05-29
Fixed
- Kubernetes injection: handle named target ports in Service resources —
targetPortcan be a string (e.g."http") not only a number. Both
inject::k8s::runandinject::k8s::scenarionow fall back to
IntOrString::Stringwhen the numeric parse fails, instead of panicking on
unwrap().
[0.19.0] - 2026-05-28
Changed
- Agent vector database: replaced Qdrant (external server) with embedded LanceDB
- Removed
qdrant-clientcrate dependency; no Docker or network server needed - LanceDB stores data locally in
.fault/lancedb— tables created implicitly on first write - Sparse vector generation removed from retrieval (LanceDB uses Tantivy for FTS)
- Removed
create_index_if_not_exists()calls from all query pipelines - All batch sizes updated to
usizeliterals to match LanceDB builder API - Custom
OpIdRetrieverstruct insuggestion.rsreplaced withSimilaritySingleEmbedding<String>using LanceDB native filter syntax (operation_id = '{opid}') HybridSearch<Filter>replaced withSimilaritySingleEmbedding<String>across all query pipelines- All Qdrant builder calls replaced with LanceDB equivalents (
.uri(),.table_name())
- Removed
[0.18.0] - 2026-05-28
Added
- Agent: Anthropic/Claude LLM client support —
--llm-client claude(alias:claude,anthropic)- Uses Claude's native Messages API via the
async-anthropiccrate - Reads
ANTHROPIC_API_KEYfrom the environment - Embedding support via local FastEmbed (Anthropic doesn't provide native embeddings)
- Uses Claude's native Messages API via the
[0.17.1] - 2026-02-27
Fixed
- ci: set
aarch64-linux-gnu-gccas linker foraarch64-unknown-linux-gnucross-compilation to fix x86_64/aarch64 ELF incompatibility error
[0.17.0] - 2026-02-27
Added
- eBPF stealth mode: new
--capture-pidflag to target a specific process by PID,
bypassing the/procname scan — essential when multiple instances of the same
process are running (e.g. multiple opencode sessions) - eBPF stealth mode: match intercepted processes by TGID instead of thread comm, fixing
capture of multi-threaded runtimes (Bun/Node) where the HTTP thread has a different
comm than the process name (e.g.HTTP Clientvsopencode) - eBPF stealth mode: skip interception of connections to
127.0.0.0/8(loopback IPC)
to avoid forwarding intra-process connections that woul...
0.20.6
Changes
[0.20.6] - 2026-06-01
Added
-
--dry-runforfault inject kubernetes— prints the full injection
plan without making any changes to the cluster.Inbound mode (
--service) shows: target service name/namespace, current
selector and ports, resources that would be created (ServiceAccount,
ConfigMap, Job, backend Service), and the Service patch that would be
applied.Standalone outbound mode (
--env-override) shows: proxy name/namespace/
upstream/listen port, resources that would be created, each env var key
with its resolved value ({host}and{port}substituted), and active
fault settings. -
Clear rollback failure output — if
plt.rollback()fails, a prominent
ERROR:message is printed to stderr with the error, the likely leftover
resources to clean up manually, and guidance on restoring the original
Service selector. The process exits with a non-zero status.
[0.20.5] - 2026-06-01
Fixed
- Ctrl-C now always triggers rollback — previously, when no
--duration
was set, the confirmation prompt (Press 'y' to finish and rollback) blocked
the async runtime synchronously. A SIGINT at that point killed the process
beforeplt.rollback()could run, leaving injected Service selectors and
proxy resources in place. The prompt is now run on a thread-pool thread via
spawn_blockingso the async runtime stays live; atokio::select!races
the prompt completion againstctrl_c(), and rollback always executes
afterward.
Added
- System service protection — the Kubernetes API server service
(kubernetesindefault) and all services in system namespaces
(kube-system,kube-public,kube-node-lease) are now excluded from the
interactive service selection list and blocked at theset_servicecall when
passed via--service. Attempting to inject into a protected service returns
a clear error message suggesting--nsif the wrong namespace was used.
[0.20.4] - 2026-06-01
Changed
-
fault inject kubernetes: HTTP error fault now forces HTTP proxy mode —
when--with-http-responseis set, the injected proxy Job runs as an HTTP
CONNECT proxy (omitting--disable-http-proxyand--proxy). This is the
only mode that can inspect and rewrite HTTP responses at L7. All other faults
continue to use TCP proxy mode (transparent, L4 only). -
--with-http-responsehelp text clarifies that HTTP error injection
requires inbound proxy mode (--service). Standalone outbound mode
(--env-overridewithout--service) cannot use HTTP error faults because
the TCP proxy has no L7 visibility.
[0.20.3] - 2026-06-01
Fixed
--env-overrideupstream resolution with split host/port keys — when
separateDB_HOST={host}andDB_PORT={port}overrides are used, the proxy
upstream was assembled from only the first key's current value, producing a
portless address (e.g.prod-db.example.cominstead of
prod-db.example.com:5432) which caused the proxy to fail to connect.
resolve_upstreamnow reads both keys and combines them intohost:port.
[0.20.2] - 2026-06-01
Changed
-
--env-overridetemplate substitution — the value now supports
{host}and{port}placeholders that fault replaces with the proxy's
in-cluster name and port (3180) at inject time. Any combination works:--env-override configmap/my-config:DB_HOST={host} --env-override configmap/my-config:DB_PORT={port} --env-override configmap/my-config:DATABASE_URL=postgres://{host}:{port}/mydb --env-override configmap/my-config:API_URL=https://{host}:{port}/v1Values without
{host}or{port}are treated as literals (unchanged
from before).
Removed
- Bare
KEYwithout=VALUE— previously accepted as an auto-inject
shorthand, now a parse error. UseKEY={host}:{port}instead.
[0.20.1] - 2026-06-01
Changed
-
--env-overrideauto proxy address injection — the value side is now
optional.kind/name:KEY(no=VALUE) instructs fault to automatically
fill in the proxy's own in-cluster address (proxy-name:3180) at inject
time, so you no longer need to know the proxy name ahead of time when using
a generated suffix. -
--env-overridevalue is nowExplicit | Auto— internally the value
field is now a typed enum; the parser accepts bothKEY=VALUEand bare
KEY.
Removed
-
--env-override-ns— dropped before it shipped. The--nsflag already
scopes everything; a separate override namespace would require cross-namespace
RBAC which is out of scope. -
Port derivation from
--env-overridevalue — the standalone proxy
always listens on port3180, consistent with the inbound proxy. The
:PORTsuffix in an explicit value is the upstream port, not the proxy's
listen port; parsing it as the proxy port was wrong.
[0.20.0] - 2026-05-29
Added
-
Kubernetes injection: outbound (standalone) proxy mode — inject faults on
traffic a pod sends to a downstream dependency (e.g. a cloud DB), not just
on inbound traffic arriving at the pod.Triggered by passing one or more
--env-overrideflags without--service.
A standalone fault proxy Job + ClusterIP Service is created; env vars in the
named ConfigMaps, Deployments, or StatefulSets are patched to redirect the
downstream address through the proxy. On rollback, original values are
restored and the proxy resources are deleted.fault inject kubernetes \ --env-override configmap/my-app-config:DB_HOST=fault-proxy-db:5432 \ --with-latency --latency-mean 200 -
--env-override kind/name:KEY=VALUE— new repeatable flag for the
Kubernetes injector. Patches a specific key in a ConfigMap, Deployment, or
StatefulSet (aliases:cm,deploy,sts). For Deployment/StatefulSet a
rolling restart annotation is added; for ConfigMap only the data key is
patched (rollout is left to the operator). Original values are stored in the
rollback snapshot and restored automatically. -
--name— optional name for the standalone proxy resources. When omitted
a short random suffix is generated (fault-proxy-<6 chars>). Useful in
scripts where the proxy address must be known ahead of time and embedded in
the--env-overridevalue.
Fixed
BandwidthUnit::from_str: match arms used mixed case ("Bps","KBps")
after.to_lowercase(), making them unreachable. Arms are now all lowercase.
[0.19.1] - 2026-05-29
Fixed
- Kubernetes injection: handle named target ports in Service resources —
targetPortcan be a string (e.g."http") not only a number. Both
inject::k8s::runandinject::k8s::scenarionow fall back to
IntOrString::Stringwhen the numeric parse fails, instead of panicking on
unwrap().
[0.19.0] - 2026-05-28
Changed
- Agent vector database: replaced Qdrant (external server) with embedded LanceDB
- Removed
qdrant-clientcrate dependency; no Docker or network server needed - LanceDB stores data locally in
.fault/lancedb— tables created implicitly on first write - Sparse vector generation removed from retrieval (LanceDB uses Tantivy for FTS)
- Removed
create_index_if_not_exists()calls from all query pipelines - All batch sizes updated to
usizeliterals to match LanceDB builder API - Custom
OpIdRetrieverstruct insuggestion.rsreplaced withSimilaritySingleEmbedding<String>using LanceDB native filter syntax (operation_id = '{opid}') HybridSearch<Filter>replaced withSimilaritySingleEmbedding<String>across all query pipelines- All Qdrant builder calls replaced with LanceDB equivalents (
.uri(),.table_name())
- Removed
[0.18.0] - 2026-05-28
Added
- Agent: Anthropic/Claude LLM client support —
--llm-client claude(alias:claude,anthropic)- Uses Claude's native Messages API via the
async-anthropiccrate - Reads
ANTHROPIC_API_KEYfrom the environment - Embedding support via local FastEmbed (Anthropic doesn't provide native embeddings)
- Uses Claude's native Messages API via the
[0.17.1] - 2026-02-27
Fixed
- ci: set
aarch64-linux-gnu-gccas linker foraarch64-unknown-linux-gnucross-compilation to fix x86_64/aarch64 ELF incompatibility error
[0.17.0] - 2026-02-27
Added
-
eBPF stealth mode: new
--capture-pidflag to target a specific process by PID,
bypassing the/procname scan — essential when multiple instances of the same
process are running (e.g. multiple opencode sessions) -
eBPF stealth mode: match intercepted processes by TGID instead of thread comm, fixing
capture of multi-threaded runtimes (Bun/Node) where the HTTP thread has a different
comm than the process name (e.g.HTTP Clientvsopencode) -
eBPF stealth mode: skip interception of connections to
127.0.0.0/8(loopback IPC)
to avoid forwarding intra-process connections that would reset -
eBPF stealth mode: treat
ConnectionResetfrom client as a normal teardown (not an
error) — Happy Eyeballs causes the losing IP-family connection to be RST'd by the
client once the winning family completes -
eBPF stealth mode: IPv6 interception support via a new
cg_connect6cgroup program- Extended
ProxyConfigandSocketBPF maps to carry IPv6 addresses - Added dual-listener proxy (separate ports for IPv4/IPv6 to avoid dual-stack bind conflicts)
- BPF redirects IPv6 connections to the machine's global IPv6 address; retrieves the original destination via
getsockopt(SOL_IPV6, IP6T_SO_ORIGINAL_DST) - All aya crates (
aya,aya-log,aya-ebpf,aya-log-ebpf,aya-build) pinned to the same git rev (c42157f0) so the BPF log ring-buffer transport is consistent between kernel and userspace
- Extended
Fixed
- bpf-linker: set
LLVM_PREFIX=/usr/lib/llvm-21when installing to fix "could not find dynamic libLLVM" error - eBPF build: fixed memcpy symbol multiply defined error by aligning aya-ebpf version (using git version to match ...
0.20.5
Changes
[0.20.5] - 2026-06-01
Fixed
- Ctrl-C now always triggers rollback — previously, when no
--duration
was set, the confirmation prompt (Press 'y' to finish and rollback) blocked
the async runtime synchronously. A SIGINT at that point killed the process
beforeplt.rollback()could run, leaving injected Service selectors and
proxy resources in place. The prompt is now run on a thread-pool thread via
spawn_blockingso the async runtime stays live; atokio::select!races
the prompt completion againstctrl_c(), and rollback always executes
afterward.
Added
- System service protection — the Kubernetes API server service
(kubernetesindefault) and all services in system namespaces
(kube-system,kube-public,kube-node-lease) are now excluded from the
interactive service selection list and blocked at theset_servicecall when
passed via--service. Attempting to inject into a protected service returns
a clear error message suggesting--nsif the wrong namespace was used.
[0.20.4] - 2026-06-01
Changed
-
fault inject kubernetes: HTTP error fault now forces HTTP proxy mode —
when--with-http-responseis set, the injected proxy Job runs as an HTTP
CONNECT proxy (omitting--disable-http-proxyand--proxy). This is the
only mode that can inspect and rewrite HTTP responses at L7. All other faults
continue to use TCP proxy mode (transparent, L4 only). -
--with-http-responsehelp text clarifies that HTTP error injection
requires inbound proxy mode (--service). Standalone outbound mode
(--env-overridewithout--service) cannot use HTTP error faults because
the TCP proxy has no L7 visibility.
[0.20.3] - 2026-06-01
Fixed
--env-overrideupstream resolution with split host/port keys — when
separateDB_HOST={host}andDB_PORT={port}overrides are used, the proxy
upstream was assembled from only the first key's current value, producing a
portless address (e.g.prod-db.example.cominstead of
prod-db.example.com:5432) which caused the proxy to fail to connect.
resolve_upstreamnow reads both keys and combines them intohost:port.
[0.20.2] - 2026-06-01
Changed
-
--env-overridetemplate substitution — the value now supports
{host}and{port}placeholders that fault replaces with the proxy's
in-cluster name and port (3180) at inject time. Any combination works:--env-override configmap/my-config:DB_HOST={host} --env-override configmap/my-config:DB_PORT={port} --env-override configmap/my-config:DATABASE_URL=postgres://{host}:{port}/mydb --env-override configmap/my-config:API_URL=https://{host}:{port}/v1Values without
{host}or{port}are treated as literals (unchanged
from before).
Removed
- Bare
KEYwithout=VALUE— previously accepted as an auto-inject
shorthand, now a parse error. UseKEY={host}:{port}instead.
[0.20.1] - 2026-06-01
Changed
-
--env-overrideauto proxy address injection — the value side is now
optional.kind/name:KEY(no=VALUE) instructs fault to automatically
fill in the proxy's own in-cluster address (proxy-name:3180) at inject
time, so you no longer need to know the proxy name ahead of time when using
a generated suffix. -
--env-overridevalue is nowExplicit | Auto— internally the value
field is now a typed enum; the parser accepts bothKEY=VALUEand bare
KEY.
Removed
-
--env-override-ns— dropped before it shipped. The--nsflag already
scopes everything; a separate override namespace would require cross-namespace
RBAC which is out of scope. -
Port derivation from
--env-overridevalue — the standalone proxy
always listens on port3180, consistent with the inbound proxy. The
:PORTsuffix in an explicit value is the upstream port, not the proxy's
listen port; parsing it as the proxy port was wrong.
[0.20.0] - 2026-05-29
Added
-
Kubernetes injection: outbound (standalone) proxy mode — inject faults on
traffic a pod sends to a downstream dependency (e.g. a cloud DB), not just
on inbound traffic arriving at the pod.Triggered by passing one or more
--env-overrideflags without--service.
A standalone fault proxy Job + ClusterIP Service is created; env vars in the
named ConfigMaps, Deployments, or StatefulSets are patched to redirect the
downstream address through the proxy. On rollback, original values are
restored and the proxy resources are deleted.fault inject kubernetes \ --env-override configmap/my-app-config:DB_HOST=fault-proxy-db:5432 \ --with-latency --latency-mean 200 -
--env-override kind/name:KEY=VALUE— new repeatable flag for the
Kubernetes injector. Patches a specific key in a ConfigMap, Deployment, or
StatefulSet (aliases:cm,deploy,sts). For Deployment/StatefulSet a
rolling restart annotation is added; for ConfigMap only the data key is
patched (rollout is left to the operator). Original values are stored in the
rollback snapshot and restored automatically. -
--name— optional name for the standalone proxy resources. When omitted
a short random suffix is generated (fault-proxy-<6 chars>). Useful in
scripts where the proxy address must be known ahead of time and embedded in
the--env-overridevalue.
Fixed
BandwidthUnit::from_str: match arms used mixed case ("Bps","KBps")
after.to_lowercase(), making them unreachable. Arms are now all lowercase.
[0.19.1] - 2026-05-29
Fixed
- Kubernetes injection: handle named target ports in Service resources —
targetPortcan be a string (e.g."http") not only a number. Both
inject::k8s::runandinject::k8s::scenarionow fall back to
IntOrString::Stringwhen the numeric parse fails, instead of panicking on
unwrap().
[0.19.0] - 2026-05-28
Changed
- Agent vector database: replaced Qdrant (external server) with embedded LanceDB
- Removed
qdrant-clientcrate dependency; no Docker or network server needed - LanceDB stores data locally in
.fault/lancedb— tables created implicitly on first write - Sparse vector generation removed from retrieval (LanceDB uses Tantivy for FTS)
- Removed
create_index_if_not_exists()calls from all query pipelines - All batch sizes updated to
usizeliterals to match LanceDB builder API - Custom
OpIdRetrieverstruct insuggestion.rsreplaced withSimilaritySingleEmbedding<String>using LanceDB native filter syntax (operation_id = '{opid}') HybridSearch<Filter>replaced withSimilaritySingleEmbedding<String>across all query pipelines- All Qdrant builder calls replaced with LanceDB equivalents (
.uri(),.table_name())
- Removed
[0.18.0] - 2026-05-28
Added
- Agent: Anthropic/Claude LLM client support —
--llm-client claude(alias:claude,anthropic)- Uses Claude's native Messages API via the
async-anthropiccrate - Reads
ANTHROPIC_API_KEYfrom the environment - Embedding support via local FastEmbed (Anthropic doesn't provide native embeddings)
- Uses Claude's native Messages API via the
[0.17.1] - 2026-02-27
Fixed
- ci: set
aarch64-linux-gnu-gccas linker foraarch64-unknown-linux-gnucross-compilation to fix x86_64/aarch64 ELF incompatibility error
[0.17.0] - 2026-02-27
Added
-
eBPF stealth mode: new
--capture-pidflag to target a specific process by PID,
bypassing the/procname scan — essential when multiple instances of the same
process are running (e.g. multiple opencode sessions) -
eBPF stealth mode: match intercepted processes by TGID instead of thread comm, fixing
capture of multi-threaded runtimes (Bun/Node) where the HTTP thread has a different
comm than the process name (e.g.HTTP Clientvsopencode) -
eBPF stealth mode: skip interception of connections to
127.0.0.0/8(loopback IPC)
to avoid forwarding intra-process connections that would reset -
eBPF stealth mode: treat
ConnectionResetfrom client as a normal teardown (not an
error) — Happy Eyeballs causes the losing IP-family connection to be RST'd by the
client once the winning family completes -
eBPF stealth mode: IPv6 interception support via a new
cg_connect6cgroup program- Extended
ProxyConfigandSocketBPF maps to carry IPv6 addresses - Added dual-listener proxy (separate ports for IPv4/IPv6 to avoid dual-stack bind conflicts)
- BPF redirects IPv6 connections to the machine's global IPv6 address; retrieves the original destination via
getsockopt(SOL_IPV6, IP6T_SO_ORIGINAL_DST) - All aya crates (
aya,aya-log,aya-ebpf,aya-log-ebpf,aya-build) pinned to the same git rev (c42157f0) so the BPF log ring-buffer transport is consistent between kernel and userspace
- Extended
Fixed
- bpf-linker: set
LLVM_PREFIX=/usr/lib/llvm-21when installing to fix "could not find dynamic libLLVM" error - eBPF build: fixed memcpy symbol multiply defined error by aligning aya-ebpf version (using git version to match aya-log-ebpf)
- fault-ebpf-programs: fixed reference error in MAP_SOCKS.get() call
Changed
- Renamed
fault/llm/openai.rstofault/llm/inject.rsand updated types:
OpenAiSettings→LlmSettings,OpenAiInjector→LlmInjector— the
module already handles both OpenAI-compatible and Anthropic/Claude APIs so the
OpenAI-specific naming was misleading - Add proper DNS fault support
Full Changelog: 0.20.4...0.20.5
0.20.4
Changes
[0.20.4] - 2026-06-01
Changed
-
fault inject kubernetes: HTTP error fault now forces HTTP proxy mode —
when--with-http-responseis set, the injected proxy Job runs as an HTTP
CONNECT proxy (omitting--disable-http-proxyand--proxy). This is the
only mode that can inspect and rewrite HTTP responses at L7. All other faults
continue to use TCP proxy mode (transparent, L4 only). -
--with-http-responsehelp text clarifies that HTTP error injection
requires inbound proxy mode (--service). Standalone outbound mode
(--env-overridewithout--service) cannot use HTTP error faults because
the TCP proxy has no L7 visibility.
[0.20.3] - 2026-06-01
Fixed
--env-overrideupstream resolution with split host/port keys — when
separateDB_HOST={host}andDB_PORT={port}overrides are used, the proxy
upstream was assembled from only the first key's current value, producing a
portless address (e.g.prod-db.example.cominstead of
prod-db.example.com:5432) which caused the proxy to fail to connect.
resolve_upstreamnow reads both keys and combines them intohost:port.
[0.20.2] - 2026-06-01
Changed
-
--env-overridetemplate substitution — the value now supports
{host}and{port}placeholders that fault replaces with the proxy's
in-cluster name and port (3180) at inject time. Any combination works:--env-override configmap/my-config:DB_HOST={host} --env-override configmap/my-config:DB_PORT={port} --env-override configmap/my-config:DATABASE_URL=postgres://{host}:{port}/mydb --env-override configmap/my-config:API_URL=https://{host}:{port}/v1Values without
{host}or{port}are treated as literals (unchanged
from before).
Removed
- Bare
KEYwithout=VALUE— previously accepted as an auto-inject
shorthand, now a parse error. UseKEY={host}:{port}instead.
[0.20.1] - 2026-06-01
Changed
-
--env-overrideauto proxy address injection — the value side is now
optional.kind/name:KEY(no=VALUE) instructs fault to automatically
fill in the proxy's own in-cluster address (proxy-name:3180) at inject
time, so you no longer need to know the proxy name ahead of time when using
a generated suffix. -
--env-overridevalue is nowExplicit | Auto— internally the value
field is now a typed enum; the parser accepts bothKEY=VALUEand bare
KEY.
Removed
-
--env-override-ns— dropped before it shipped. The--nsflag already
scopes everything; a separate override namespace would require cross-namespace
RBAC which is out of scope. -
Port derivation from
--env-overridevalue — the standalone proxy
always listens on port3180, consistent with the inbound proxy. The
:PORTsuffix in an explicit value is the upstream port, not the proxy's
listen port; parsing it as the proxy port was wrong.
[0.20.0] - 2026-05-29
Added
-
Kubernetes injection: outbound (standalone) proxy mode — inject faults on
traffic a pod sends to a downstream dependency (e.g. a cloud DB), not just
on inbound traffic arriving at the pod.Triggered by passing one or more
--env-overrideflags without--service.
A standalone fault proxy Job + ClusterIP Service is created; env vars in the
named ConfigMaps, Deployments, or StatefulSets are patched to redirect the
downstream address through the proxy. On rollback, original values are
restored and the proxy resources are deleted.fault inject kubernetes \ --env-override configmap/my-app-config:DB_HOST=fault-proxy-db:5432 \ --with-latency --latency-mean 200 -
--env-override kind/name:KEY=VALUE— new repeatable flag for the
Kubernetes injector. Patches a specific key in a ConfigMap, Deployment, or
StatefulSet (aliases:cm,deploy,sts). For Deployment/StatefulSet a
rolling restart annotation is added; for ConfigMap only the data key is
patched (rollout is left to the operator). Original values are stored in the
rollback snapshot and restored automatically. -
--name— optional name for the standalone proxy resources. When omitted
a short random suffix is generated (fault-proxy-<6 chars>). Useful in
scripts where the proxy address must be known ahead of time and embedded in
the--env-overridevalue.
Fixed
BandwidthUnit::from_str: match arms used mixed case ("Bps","KBps")
after.to_lowercase(), making them unreachable. Arms are now all lowercase.
[0.19.1] - 2026-05-29
Fixed
- Kubernetes injection: handle named target ports in Service resources —
targetPortcan be a string (e.g."http") not only a number. Both
inject::k8s::runandinject::k8s::scenarionow fall back to
IntOrString::Stringwhen the numeric parse fails, instead of panicking on
unwrap().
[0.19.0] - 2026-05-28
Changed
- Agent vector database: replaced Qdrant (external server) with embedded LanceDB
- Removed
qdrant-clientcrate dependency; no Docker or network server needed - LanceDB stores data locally in
.fault/lancedb— tables created implicitly on first write - Sparse vector generation removed from retrieval (LanceDB uses Tantivy for FTS)
- Removed
create_index_if_not_exists()calls from all query pipelines - All batch sizes updated to
usizeliterals to match LanceDB builder API - Custom
OpIdRetrieverstruct insuggestion.rsreplaced withSimilaritySingleEmbedding<String>using LanceDB native filter syntax (operation_id = '{opid}') HybridSearch<Filter>replaced withSimilaritySingleEmbedding<String>across all query pipelines- All Qdrant builder calls replaced with LanceDB equivalents (
.uri(),.table_name())
- Removed
[0.18.0] - 2026-05-28
Added
- Agent: Anthropic/Claude LLM client support —
--llm-client claude(alias:claude,anthropic)- Uses Claude's native Messages API via the
async-anthropiccrate - Reads
ANTHROPIC_API_KEYfrom the environment - Embedding support via local FastEmbed (Anthropic doesn't provide native embeddings)
- Uses Claude's native Messages API via the
[0.17.1] - 2026-02-27
Fixed
- ci: set
aarch64-linux-gnu-gccas linker foraarch64-unknown-linux-gnucross-compilation to fix x86_64/aarch64 ELF incompatibility error
[0.17.0] - 2026-02-27
Added
-
eBPF stealth mode: new
--capture-pidflag to target a specific process by PID,
bypassing the/procname scan — essential when multiple instances of the same
process are running (e.g. multiple opencode sessions) -
eBPF stealth mode: match intercepted processes by TGID instead of thread comm, fixing
capture of multi-threaded runtimes (Bun/Node) where the HTTP thread has a different
comm than the process name (e.g.HTTP Clientvsopencode) -
eBPF stealth mode: skip interception of connections to
127.0.0.0/8(loopback IPC)
to avoid forwarding intra-process connections that would reset -
eBPF stealth mode: treat
ConnectionResetfrom client as a normal teardown (not an
error) — Happy Eyeballs causes the losing IP-family connection to be RST'd by the
client once the winning family completes -
eBPF stealth mode: IPv6 interception support via a new
cg_connect6cgroup program- Extended
ProxyConfigandSocketBPF maps to carry IPv6 addresses - Added dual-listener proxy (separate ports for IPv4/IPv6 to avoid dual-stack bind conflicts)
- BPF redirects IPv6 connections to the machine's global IPv6 address; retrieves the original destination via
getsockopt(SOL_IPV6, IP6T_SO_ORIGINAL_DST) - All aya crates (
aya,aya-log,aya-ebpf,aya-log-ebpf,aya-build) pinned to the same git rev (c42157f0) so the BPF log ring-buffer transport is consistent between kernel and userspace
- Extended
Fixed
- bpf-linker: set
LLVM_PREFIX=/usr/lib/llvm-21when installing to fix "could not find dynamic libLLVM" error - eBPF build: fixed memcpy symbol multiply defined error by aligning aya-ebpf version (using git version to match aya-log-ebpf)
- fault-ebpf-programs: fixed reference error in MAP_SOCKS.get() call
Changed
- Renamed
fault/llm/openai.rstofault/llm/inject.rsand updated types:
OpenAiSettings→LlmSettings,OpenAiInjector→LlmInjector— the
module already handles both OpenAI-compatible and Anthropic/Claude APIs so the
OpenAI-specific naming was misleading - Add proper DNS fault support
Full Changelog: 0.20.3...0.20.4
0.20.3
Changes
[0.20.3] - 2026-06-01
Fixed
--env-overrideupstream resolution with split host/port keys — when
separateDB_HOST={host}andDB_PORT={port}overrides are used, the proxy
upstream was assembled from only the first key's current value, producing a
portless address (e.g.prod-db.example.cominstead of
prod-db.example.com:5432) which caused the proxy to fail to connect.
resolve_upstreamnow reads both keys and combines them intohost:port.
[0.20.2] - 2026-06-01
Changed
-
--env-overridetemplate substitution — the value now supports
{host}and{port}placeholders that fault replaces with the proxy's
in-cluster name and port (3180) at inject time. Any combination works:--env-override configmap/my-config:DB_HOST={host} --env-override configmap/my-config:DB_PORT={port} --env-override configmap/my-config:DATABASE_URL=postgres://{host}:{port}/mydb --env-override configmap/my-config:API_URL=https://{host}:{port}/v1Values without
{host}or{port}are treated as literals (unchanged
from before).
Removed
- Bare
KEYwithout=VALUE— previously accepted as an auto-inject
shorthand, now a parse error. UseKEY={host}:{port}instead.
[0.20.1] - 2026-06-01
Changed
-
--env-overrideauto proxy address injection — the value side is now
optional.kind/name:KEY(no=VALUE) instructs fault to automatically
fill in the proxy's own in-cluster address (proxy-name:3180) at inject
time, so you no longer need to know the proxy name ahead of time when using
a generated suffix. -
--env-overridevalue is nowExplicit | Auto— internally the value
field is now a typed enum; the parser accepts bothKEY=VALUEand bare
KEY.
Removed
-
--env-override-ns— dropped before it shipped. The--nsflag already
scopes everything; a separate override namespace would require cross-namespace
RBAC which is out of scope. -
Port derivation from
--env-overridevalue — the standalone proxy
always listens on port3180, consistent with the inbound proxy. The
:PORTsuffix in an explicit value is the upstream port, not the proxy's
listen port; parsing it as the proxy port was wrong.
[0.20.0] - 2026-05-29
Added
-
Kubernetes injection: outbound (standalone) proxy mode — inject faults on
traffic a pod sends to a downstream dependency (e.g. a cloud DB), not just
on inbound traffic arriving at the pod.Triggered by passing one or more
--env-overrideflags without--service.
A standalone fault proxy Job + ClusterIP Service is created; env vars in the
named ConfigMaps, Deployments, or StatefulSets are patched to redirect the
downstream address through the proxy. On rollback, original values are
restored and the proxy resources are deleted.fault inject kubernetes \ --env-override configmap/my-app-config:DB_HOST=fault-proxy-db:5432 \ --with-latency --latency-mean 200 -
--env-override kind/name:KEY=VALUE— new repeatable flag for the
Kubernetes injector. Patches a specific key in a ConfigMap, Deployment, or
StatefulSet (aliases:cm,deploy,sts). For Deployment/StatefulSet a
rolling restart annotation is added; for ConfigMap only the data key is
patched (rollout is left to the operator). Original values are stored in the
rollback snapshot and restored automatically. -
--name— optional name for the standalone proxy resources. When omitted
a short random suffix is generated (fault-proxy-<6 chars>). Useful in
scripts where the proxy address must be known ahead of time and embedded in
the--env-overridevalue.
Fixed
BandwidthUnit::from_str: match arms used mixed case ("Bps","KBps")
after.to_lowercase(), making them unreachable. Arms are now all lowercase.
[0.19.1] - 2026-05-29
Fixed
- Kubernetes injection: handle named target ports in Service resources —
targetPortcan be a string (e.g."http") not only a number. Both
inject::k8s::runandinject::k8s::scenarionow fall back to
IntOrString::Stringwhen the numeric parse fails, instead of panicking on
unwrap().
[0.19.0] - 2026-05-28
Changed
- Agent vector database: replaced Qdrant (external server) with embedded LanceDB
- Removed
qdrant-clientcrate dependency; no Docker or network server needed - LanceDB stores data locally in
.fault/lancedb— tables created implicitly on first write - Sparse vector generation removed from retrieval (LanceDB uses Tantivy for FTS)
- Removed
create_index_if_not_exists()calls from all query pipelines - All batch sizes updated to
usizeliterals to match LanceDB builder API - Custom
OpIdRetrieverstruct insuggestion.rsreplaced withSimilaritySingleEmbedding<String>using LanceDB native filter syntax (operation_id = '{opid}') HybridSearch<Filter>replaced withSimilaritySingleEmbedding<String>across all query pipelines- All Qdrant builder calls replaced with LanceDB equivalents (
.uri(),.table_name())
- Removed
[0.18.0] - 2026-05-28
Added
- Agent: Anthropic/Claude LLM client support —
--llm-client claude(alias:claude,anthropic)- Uses Claude's native Messages API via the
async-anthropiccrate - Reads
ANTHROPIC_API_KEYfrom the environment - Embedding support via local FastEmbed (Anthropic doesn't provide native embeddings)
- Uses Claude's native Messages API via the
[0.17.1] - 2026-02-27
Fixed
- ci: set
aarch64-linux-gnu-gccas linker foraarch64-unknown-linux-gnucross-compilation to fix x86_64/aarch64 ELF incompatibility error
[0.17.0] - 2026-02-27
Added
-
eBPF stealth mode: new
--capture-pidflag to target a specific process by PID,
bypassing the/procname scan — essential when multiple instances of the same
process are running (e.g. multiple opencode sessions) -
eBPF stealth mode: match intercepted processes by TGID instead of thread comm, fixing
capture of multi-threaded runtimes (Bun/Node) where the HTTP thread has a different
comm than the process name (e.g.HTTP Clientvsopencode) -
eBPF stealth mode: skip interception of connections to
127.0.0.0/8(loopback IPC)
to avoid forwarding intra-process connections that would reset -
eBPF stealth mode: treat
ConnectionResetfrom client as a normal teardown (not an
error) — Happy Eyeballs causes the losing IP-family connection to be RST'd by the
client once the winning family completes -
eBPF stealth mode: IPv6 interception support via a new
cg_connect6cgroup program- Extended
ProxyConfigandSocketBPF maps to carry IPv6 addresses - Added dual-listener proxy (separate ports for IPv4/IPv6 to avoid dual-stack bind conflicts)
- BPF redirects IPv6 connections to the machine's global IPv6 address; retrieves the original destination via
getsockopt(SOL_IPV6, IP6T_SO_ORIGINAL_DST) - All aya crates (
aya,aya-log,aya-ebpf,aya-log-ebpf,aya-build) pinned to the same git rev (c42157f0) so the BPF log ring-buffer transport is consistent between kernel and userspace
- Extended
Fixed
- bpf-linker: set
LLVM_PREFIX=/usr/lib/llvm-21when installing to fix "could not find dynamic libLLVM" error - eBPF build: fixed memcpy symbol multiply defined error by aligning aya-ebpf version (using git version to match aya-log-ebpf)
- fault-ebpf-programs: fixed reference error in MAP_SOCKS.get() call
Changed
- Renamed
fault/llm/openai.rstofault/llm/inject.rsand updated types:
OpenAiSettings→LlmSettings,OpenAiInjector→LlmInjector— the
module already handles both OpenAI-compatible and Anthropic/Claude APIs so the
OpenAI-specific naming was misleading - Add proper DNS fault support
Full Changelog: 0.20.2...0.20.3
0.20.2
Changes
[0.20.2] - 2026-06-01
Changed
-
--env-overridetemplate substitution — the value now supports
{host}and{port}placeholders that fault replaces with the proxy's
in-cluster name and port (3180) at inject time. Any combination works:--env-override configmap/my-config:DB_HOST={host} --env-override configmap/my-config:DB_PORT={port} --env-override configmap/my-config:DATABASE_URL=postgres://{host}:{port}/mydb --env-override configmap/my-config:API_URL=https://{host}:{port}/v1Values without
{host}or{port}are treated as literals (unchanged
from before).
Removed
- Bare
KEYwithout=VALUE— previously accepted as an auto-inject
shorthand, now a parse error. UseKEY={host}:{port}instead.
[0.20.1] - 2026-06-01
Changed
-
--env-overrideauto proxy address injection — the value side is now
optional.kind/name:KEY(no=VALUE) instructs fault to automatically
fill in the proxy's own in-cluster address (proxy-name:3180) at inject
time, so you no longer need to know the proxy name ahead of time when using
a generated suffix. -
--env-overridevalue is nowExplicit | Auto— internally the value
field is now a typed enum; the parser accepts bothKEY=VALUEand bare
KEY.
Removed
-
--env-override-ns— dropped before it shipped. The--nsflag already
scopes everything; a separate override namespace would require cross-namespace
RBAC which is out of scope. -
Port derivation from
--env-overridevalue — the standalone proxy
always listens on port3180, consistent with the inbound proxy. The
:PORTsuffix in an explicit value is the upstream port, not the proxy's
listen port; parsing it as the proxy port was wrong.
[0.20.0] - 2026-05-29
Added
-
Kubernetes injection: outbound (standalone) proxy mode — inject faults on
traffic a pod sends to a downstream dependency (e.g. a cloud DB), not just
on inbound traffic arriving at the pod.Triggered by passing one or more
--env-overrideflags without--service.
A standalone fault proxy Job + ClusterIP Service is created; env vars in the
named ConfigMaps, Deployments, or StatefulSets are patched to redirect the
downstream address through the proxy. On rollback, original values are
restored and the proxy resources are deleted.fault inject kubernetes \ --env-override configmap/my-app-config:DB_HOST=fault-proxy-db:5432 \ --with-latency --latency-mean 200 -
--env-override kind/name:KEY=VALUE— new repeatable flag for the
Kubernetes injector. Patches a specific key in a ConfigMap, Deployment, or
StatefulSet (aliases:cm,deploy,sts). For Deployment/StatefulSet a
rolling restart annotation is added; for ConfigMap only the data key is
patched (rollout is left to the operator). Original values are stored in the
rollback snapshot and restored automatically. -
--name— optional name for the standalone proxy resources. When omitted
a short random suffix is generated (fault-proxy-<6 chars>). Useful in
scripts where the proxy address must be known ahead of time and embedded in
the--env-overridevalue.
Fixed
BandwidthUnit::from_str: match arms used mixed case ("Bps","KBps")
after.to_lowercase(), making them unreachable. Arms are now all lowercase.
[0.19.1] - 2026-05-29
Fixed
- Kubernetes injection: handle named target ports in Service resources —
targetPortcan be a string (e.g."http") not only a number. Both
inject::k8s::runandinject::k8s::scenarionow fall back to
IntOrString::Stringwhen the numeric parse fails, instead of panicking on
unwrap().
[0.19.0] - 2026-05-28
Changed
- Agent vector database: replaced Qdrant (external server) with embedded LanceDB
- Removed
qdrant-clientcrate dependency; no Docker or network server needed - LanceDB stores data locally in
.fault/lancedb— tables created implicitly on first write - Sparse vector generation removed from retrieval (LanceDB uses Tantivy for FTS)
- Removed
create_index_if_not_exists()calls from all query pipelines - All batch sizes updated to
usizeliterals to match LanceDB builder API - Custom
OpIdRetrieverstruct insuggestion.rsreplaced withSimilaritySingleEmbedding<String>using LanceDB native filter syntax (operation_id = '{opid}') HybridSearch<Filter>replaced withSimilaritySingleEmbedding<String>across all query pipelines- All Qdrant builder calls replaced with LanceDB equivalents (
.uri(),.table_name())
- Removed
[0.18.0] - 2026-05-28
Added
- Agent: Anthropic/Claude LLM client support —
--llm-client claude(alias:claude,anthropic)- Uses Claude's native Messages API via the
async-anthropiccrate - Reads
ANTHROPIC_API_KEYfrom the environment - Embedding support via local FastEmbed (Anthropic doesn't provide native embeddings)
- Uses Claude's native Messages API via the
[0.17.1] - 2026-02-27
Fixed
- ci: set
aarch64-linux-gnu-gccas linker foraarch64-unknown-linux-gnucross-compilation to fix x86_64/aarch64 ELF incompatibility error
[0.17.0] - 2026-02-27
Added
-
eBPF stealth mode: new
--capture-pidflag to target a specific process by PID,
bypassing the/procname scan — essential when multiple instances of the same
process are running (e.g. multiple opencode sessions) -
eBPF stealth mode: match intercepted processes by TGID instead of thread comm, fixing
capture of multi-threaded runtimes (Bun/Node) where the HTTP thread has a different
comm than the process name (e.g.HTTP Clientvsopencode) -
eBPF stealth mode: skip interception of connections to
127.0.0.0/8(loopback IPC)
to avoid forwarding intra-process connections that would reset -
eBPF stealth mode: treat
ConnectionResetfrom client as a normal teardown (not an
error) — Happy Eyeballs causes the losing IP-family connection to be RST'd by the
client once the winning family completes -
eBPF stealth mode: IPv6 interception support via a new
cg_connect6cgroup program- Extended
ProxyConfigandSocketBPF maps to carry IPv6 addresses - Added dual-listener proxy (separate ports for IPv4/IPv6 to avoid dual-stack bind conflicts)
- BPF redirects IPv6 connections to the machine's global IPv6 address; retrieves the original destination via
getsockopt(SOL_IPV6, IP6T_SO_ORIGINAL_DST) - All aya crates (
aya,aya-log,aya-ebpf,aya-log-ebpf,aya-build) pinned to the same git rev (c42157f0) so the BPF log ring-buffer transport is consistent between kernel and userspace
- Extended
Fixed
- bpf-linker: set
LLVM_PREFIX=/usr/lib/llvm-21when installing to fix "could not find dynamic libLLVM" error - eBPF build: fixed memcpy symbol multiply defined error by aligning aya-ebpf version (using git version to match aya-log-ebpf)
- fault-ebpf-programs: fixed reference error in MAP_SOCKS.get() call
Changed
- Renamed
fault/llm/openai.rstofault/llm/inject.rsand updated types:
OpenAiSettings→LlmSettings,OpenAiInjector→LlmInjector— the
module already handles both OpenAI-compatible and Anthropic/Claude APIs so the
OpenAI-specific naming was misleading - Add proper DNS fault support
Full Changelog: 0.20.1...0.20.2