RepoPilot

signalapp/libsignal

Home to the Signal Protocol as well as other cryptographic primitives which make Signal possible.

Healthy

Healthy across the board

ConcernsDependency

copyleft license (AGPL-3.0) — review compatibility

HealthyFork & modify

Has a license, tests, and CI — clean foundation to fork and modify.

HealthyLearn from

Documented and popular — useful reference codebase to read through.

HealthyDeploy as-is

No critical CVEs, sane security posture — runnable as-is.

  • AGPL-3.0 is copyleft — check downstream compatibility
  • Last commit 2d ago
  • 6 active contributors
  • Distributed ownership (top contributor 48% of recent commits)
  • AGPL-3.0 licensed
  • CI configured
  • Tests present

What would improve this?

  • Use as dependency ConcernsMixed if: relicense under MIT/Apache-2.0 (rare for established libs)

Computed from maintenance signals — commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/signalapp/libsignal)](https://repopilot.app/r/signalapp/libsignal)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card

This card auto-renders when someone shares https://repopilot.app/r/signalapp/libsignal on X, Slack, or LinkedIn.

Ask AI about signalapp/libsignal

Grounded in the actual source code. Pick a starter question or write your own.

Or write your own question →

Onboarding doc

Onboarding: signalapp/libsignal

Generated by RepoPilot · 2026-06-24 · Source

🎯Verdict

GO — Healthy across the board

  • Last commit 2d ago
  • 6 active contributors
  • Distributed ownership (top contributor 48% of recent commits)
  • AGPL-3.0 licensed
  • CI configured
  • Tests present
  • ⚠ AGPL-3.0 is copyleft — check downstream compatibility

<sub>Computed from maintenance signals — commit recency, contributor breadth, bus factor, license, CI, tests</sub>

TL;DR

libsignal is the cryptographic backbone of the Signal messaging app, providing platform-agnostic Rust implementations of the Signal Protocol (Double Ratchet algorithm), zero-knowledge proof systems (zkgroup), and supporting primitives like AES-GCM encryption. It exposes these capabilities via Java, Swift, and TypeScript bindings for use in Signal's Android, iOS, and Desktop clients, as well as server-side infrastructure. Monorepo organized under rust/ with domain-specific crates: rust/protocol/ (Signal Protocol), rust/zkgroup/ and rust/zkcredential/ (zero-knowledge systems), rust/crypto/ (primitives), rust/account-keys/ (PIN/SVR), rust/device-transfer/, rust/media/, etc. Language-specific bridges: rust/bridge/jni/ (Android/Java), rust/bridge/ffi/ (Swift/C), rust/bridge/node/ (TypeScript/Node). Cross-platform support via Cargo workspace members defined in Cargo.toml.

👥Who it's for

Signal app developers (Android/iOS/Desktop engineers and server-side backend teams) who need production-grade end-to-end encrypted messaging, device-to-device transfers, and zero-knowledge group features. Also used by protocol researchers and cryptographers validating the implementation.

🌱Maturity & risk

Highly mature and production-critical. The repo shows active development (0.93.2 version, recent CI/CD infrastructure with multiple GitHub Actions workflows, comprehensive test suites including slow_tests.yml and android_integration.yml). Used in millions of Signal app installations daily. Risk: breaking changes are acknowledged as possible per RELEASE.md, so upgrades require coordination.

Low technical risk for maintenance (large active Signal team, regular releases tracked in RELEASE_NOTES.md). Medium operational risk: this is security-critical cryptographic code—any vulnerability affects all Signal clients worldwide. The AGPL-3.0-only license restricts proprietary use. No single-maintainer dependency visible in the structure, but cryptography expertise is a prerequisite for contributions.

Active areas of work

Active development across multiple platforms. CI pipelines track android_integration.yml, ios_artifacts.yml, jni_artifacts.yml, npm.yml (TypeScript bindings), and lints.yml. Recent version is 0.93.2. TESTING.md and CODING_GUIDELINES.md are maintained, indicating ongoing contributor onboarding. Acknowledgments system (acknowledgments/ dir with platform-specific .md and .plist files) suggests active tracking of dependencies.

🚀Get running

git clone https://github.com/signalapp/libsignal.git
cd libsignal
# Install Rust (required, min version 1.88 per Cargo.toml)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# For Java/JNI targets, also install Android NDK
# For Swift targets, ensure Xcode is installed
# For TypeScript, install Node.js (see .nvmrc for version)
cargo build
cargo test

Daily commands:

# Run Rust tests (all default workspace members)
cargo test
# Run specific crate tests (e.g., protocol)
cargo test -p libsignal-protocol
# Build Java artifacts (requires JDK + Android NDK)
cd java && ./gradlew build
# Build Swift/iOS artifacts
cd swift && ./build_xcframework.sh
# Build TypeScript/Node.js bindings
cd node && npm install && npm test
# Check code style
cargo clippy --all-targets
cargo fmt --check

🗺️Map of the codebase

  • Cargo.toml — Workspace root defining all member crates (protocol, crypto, zkgroup, etc.); essential for understanding project structure and dependencies.
  • rust/protocol/src/lib.rs — Core Signal Protocol implementation entry point; contains the Double Ratchet algorithm and session management logic that all clients depend on.
  • rust/bridge/ffi/src/lib.rs — FFI bridge exposing Rust APIs to C/Java/Swift; critical for understanding how cryptographic primitives are surfaced to client applications.
  • rust/zkgroup/src/lib.rs — Zero-knowledge group proofs and credentials; fundamental for Signal's privacy-preserving group features and sealed sender.
  • rust/crypto/src/lib.rs — Low-level cryptographic primitives (AES-GCM, HMAC, etc.); load-bearing dependency for protocol and all higher-level modules.
  • CODING_GUIDELINES.md — Documents coding standards, safety requirements, and contribution conventions specific to this safety-critical cryptographic codebase.
  • .github/workflows/build_and_test.yml — Primary CI/CD pipeline validating all commits across Rust, Java, Swift, and Node.js bindings.

🛠️How to make changes

Add a new cryptographic primitive

  1. Create new module in rust/crypto/src with algorithm implementation (rust/crypto/src/lib.rs)
  2. Expose via FFI bridge with C bindings (rust/bridge/ffi/src/lib.rs)
  3. Add JNI wrapper for Java/Android access (rust/bridge/jni/impl/src/lib.rs)
  4. Write integration tests in respective bridge test directories (.github/workflows/build_and_test.yml)

Add a new Protocol feature (e.g., new key exchange)

  1. Implement feature in rust/protocol/src with comprehensive unit tests (rust/protocol/src/lib.rs)
  2. Update session state serialization if needed (rust/protocol/src/state.rs)
  3. Expose new session method via FFI and JNI bridges (rust/bridge/ffi/src/lib.rs)
  4. Add cross-platform integration tests (.github/workflows/build_and_test.yml)

Add a new Zero-Knowledge proof scheme

  1. Implement proof logic in rust/zkgroup/src or rust/zkcredential/src (rust/zkgroup/src/lib.rs)
  2. Add poksho proof-of-knowledge helpers if needed (rust/poksho/src/lib.rs)
  3. Expose verifiers/generators via FFI with serialization (rust/bridge/ffi/src/lib.rs)
  4. Create comprehensive test vectors and cross-platform verification tests (rust/zkgroup/tests/)

Integrate new language binding (e.g., Python)

  1. Create bridge module analogous to rust/bridge/node (rust/bridge/python/src/lib.rs)
  2. Define PyO3 FFI surface exposing core types from ffi bridge (rust/bridge/ffi/src/lib.rs)
  3. Add CI/CD workflow for building and testing Python bindings (.github/workflows/build_and_test.yml)

🔧Why these technologies

  • Rust — Memory safety without GC; critical for cryptographic code where side-channel resistance and bounds checking prevent exploits; enables FFI to C and language bindings (JNI, Swift, Node.js).
  • Signal Protocol (Double Ratchet) — Forward secrecy and break-in recovery for messaging; foundational algorithm ensuring security even if long-term keys are compromised.
  • Zero-Knowledge Proofs (ZKGroup, ZKCredential) — Enable privacy-preserving group membership, sealed sender, and username lookup without revealing user identity to server.
  • RustCrypto primitives + custom implementations — Leverage battle-tested AEAD (AES-GCM) and hashing, but implement custom algorithms where Signal's security or performance needs differ from general-purpose libraries.
  • Remote Attestation (SGX/HSM) — Verify Signal servers run correct code in trusted execution environments; cryptographically prove server integrity.

⚖️Trade-offs already made

  • Rust for core, language bindings for clients (Java/Swift/TypeScript)

    • Why: Single source of truth for cryptographic logic; avoid duplicating complex protocol state machines in each language.
    • Consequence: FFI/JNI overhead (~1–2 µs per call) but negligible for cryptographic operations; easier to audit security-critical code.
  • Custom ZK proof implementations instead of reusing generic libraries

    • Why: Signal's privacy model requires specific proof statements and credential schemes (groups, sealed sender, usernames).
    • Consequence: Higher maintenance burden; proof schemes must be carefully designed to avoid information leakage and support efficient verifiers.
  • Modular workspace structure (protocol, crypto, zkgroup, etc. as separate crates)

    • Why: Decouple concerns; clients can use only Signal Protocol without ZK overhead; facilitates independent testing and potential library reuse.
    • Consequence: More complex dependency management; duplicated abstractions; higher cognitive load for contributors.
  • C FFI as the universal bridge (JNI, Swift, Node.js all use C bindings)

    • Why: C is the lowest common denominator; reduces binding maintenance surface.
    • Consequence: Extra layer of indirection; potential performance cost; must carefully manage memory ownership across FFI boundary.

🚫Non-goals (don't propose these)

  • Not a full-stack messaging application; provides only cryptographic and protocol primitives for Signal clients to use.
  • Not a user-facing SDK; intended for integration into Signal official clients and servers, not third-party apps.
  • Does not implement network transport or server-side logic; focuses on client-side crypto and key management.
  • Does not handle account creation, registration, or directory lookups beyond ZK proof verification; server infrastructure is separate.
  • Not a cryptographic library for general use; algorithms are optimized specifically for Signal's threat model and are not stable for external consumers.

🪤Traps & gotchas

Rust version pinning: Minimum 1.88 required (Cargo.toml); older toolchains will fail. JNI/Android: Requires Android NDK (version tracked elsewhere, check CI); building Java bindings without NDK silently skips JNI compilation. Test coverage variance: TESTING.md references slow_tests.yml (separate workflow) that may not run on every PR—slow tests can hide issues. FFI stability: rust/bridge/ffi/ exports C symbols that must remain binary-compatible across iOS releases; cbindgen regeneration is version-controlled (.cbindgen-version file). Workspace features: Cargo resolver = 2 prevents dev-dependency features from leaking into release builds—be careful with conditional compilation. No Docker for dev: .dockerignore exists but main dev loop is native Rust + platform SDKs, not containerized.

🏗️Architecture

💡Concepts to learn

  • Double Ratchet Algorithm — The cryptographic core of Signal Protocol—enables forward secrecy and break-in recovery in encrypted conversations; understanding it is mandatory for reviewing rust/protocol/ changes
  • Zero-Knowledge Proofs (zkgroup, zkcredential) — Enables private group membership and profiles without revealing identity; implemented in rust/zkgroup/ and rust/zkcredential/, critical to Signal's privacy model
  • JNI (Java Native Interface) Bridging — rust/bridge/jni/ translates between Rust types and Java objects at the Android boundary; mishandled JNI can cause crashes or memory leaks in Android clients
  • FFI (Foreign Function Interface) — rust/bridge/ffi/ exposes C types and functions to Swift; maintaining binary compatibility and proper memory management is critical for iOS stability
  • Proof-of-Knowledge, Stateful-Hash-Object (poksho) — Rust crate (rust/poksho/) providing utilities for zero-knowledge proof construction; underpins zkgroup and zkcredential implementations
  • Secure Value Recovery (account-keys) — rust/account-keys/ implements PIN-based key derivation for Signal's encrypted PIN/recovery code system; knowledge of PBKDF2 and HSM attestation is relevant
  • CBIndgen Code Generation — libsignal uses cbindgen (tracked in .cbindgen-version) to auto-generate C headers from Rust; changes to Rust FFI signatures trigger header regeneration, critical for Swift integration
  • signalapp/Signal-Android — Official Signal Android client; primary consumer of libsignal's Java/JNI bindings for encrypted messaging and zkgroup features
  • signalapp/Signal-iOS — Official Signal iOS client; primary consumer of libsignal's Swift/FFI bindings
  • signalapp/Signal-Desktop — Official Signal Desktop client; primary consumer of libsignal's TypeScript/Node.js bindings via rust/bridge/node/
  • signalapp/libsignal-protocol-java — Predecessor to this repo's rust/protocol/ crate—archived, replaced by libsignal's Rust implementation and Java bindings
  • signalapp/Noise — Complementary repository for Noise protocol (used in Signal's handshake layer); libsignal focuses on Double Ratchet and higher-level constructs

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive CI workflow for rust/net/grpc module testing and documentation

The workspace includes libsignal-net-grpc as a dependency in Cargo.toml, but there is no dedicated GitHub Actions workflow for testing gRPC-specific functionality. The build_and_test.yml likely covers it, but the repo lacks explicit gRPC integration tests and a documented gRPC API surface. This is critical for a cryptographic library that exposes network primitives. The referenced rust/net/chat and rust/net/infra modules suggest gRPC is a core component but lacks visibility in CI.

  • [ ] Create .github/workflows/grpc_tests.yml to run cargo test on rust/net/grpc with gRPC-specific test flags
  • [ ] Add gRPC protocol buffer compilation verification step in the workflow
  • [ ] Document gRPC API surface in doc/ directory with examples from rust/net/grpc/src/
  • [ ] Add a check-cfg entry in Cargo.toml for any gRPC-specific feature flags used in the module

Implement missing unit tests for rust/bridge/ffi FFI boundary safety

The repo exposes Rust APIs through FFI (Foreign Function Interface) for multiple platforms (Java/JNI, Node.js, Swift/iOS), but the TESTING.md and .github/workflows/ structure show no dedicated FFI safety tests. With cryptographic code crossing language boundaries, FFI contract violations could silently corrupt data or leak keys. The rust/bridge/ffi crate is core infrastructure but likely lacks systematic tests for pointer validity, memory layout, and panic safety.

  • [ ] Review rust/bridge/ffi/src/ for undocumented safety assumptions in #[no_mangle] extern functions
  • [ ] Create rust/bridge/ffi/tests/ffi_safety_tests.rs with miri-enabled tests for pointer alignment and lifetime safety
  • [ ] Add a GitHub Actions step in build_and_test.yml to run: cargo +nightly miri test -p libsignal-ffi
  • [ ] Document FFI invariants in CODING_GUIDELINES.md section for contributors adding new FFI surfaces

Add vulnerability scanning for transitive dependencies in the acknowledgments workflow

The repo contains cargo-audit configuration (.cargo/audit.toml) and has acknowledgments infrastructure, but .github/workflows/ shows no explicit dependency vulnerability scanning for known CVEs in transitive dependencies. With multiple cryptographic crates and platform-specific bindings, a supply-chain vulnerability in a transitive dependency (e.g., a tokio version used by libsignal-net) could affect all Signal clients. The check_versions.yml workflow exists but doesn't appear to check CVE databases.

  • [ ] Create or enhance .github/workflows/dependency_audit.yml to run: cargo audit --deny warnings on every PR
  • [ ] Add cargo-deny configuration (deny.toml) to check advisories, licenses, and bans for unsafe crates, referenced in Cargo.toml
  • [ ] Integrate cargo-deny check into the workflow with per-crate license validation for AGPL-3.0 compliance
  • [ ] Document the CVE scanning process in SECURITY.md with instructions for maintainers to respond to new advisories

🌿Good first issues

  • Add comprehensive doctests for rust/crypto/ public APIs: The crypto primitives crate lacks inline documentation examples; contributors can add doc comments with runnable examples (/// ```rust) to rust/crypto/src/ modules, improving discoverability without touching security-critical code paths
  • Expand TESTING.md with platform-specific test walkthroughs: Current TESTING.md covers general strategy but lacks concrete Android NDK / Xcode / Node.js setup instructions; a new contributor can document exact steps to run JNI / FFI / Node.js tests locally, reducing onboarding friction
  • Add missing bridging layer tests for error propagation: rust/bridge/{jni,ffi,node}/ convert Rust errors to language-specific exceptions; contributors can write integration tests ensuring a Rust::SignalError correctly becomes Java.SignalException, Swift.SignalError, etc., catching hand-off bugs early

Top contributors

Click to expand

📝Recent commits

Click to expand
  • bbc1688 — net: Stop processing websocket events on H2 GOAWAY (jrose-signal)
  • 29adeae — node: Support non-ASCII usernames and passwords in proxy URLs (jrose-signal)
  • df8cf83 — node: Bridge SVR2-related code (moiseev-signal)
  • 0929fa7 — net: Add a test for H2+WS behavior with H2 GOAWAY (graceful shutdown) (jrose-signal)
  • b6ae27f — Bump hickory-proto to 0.26.1 (andrew-signal)
  • 16a1b80 — New SVR enclaves (gram-signal)
  • 191f78b — CDSI - update production enclave. (gram-signal)
  • dc72d43 — Improve dev ergonomics around acknowledgements (andrew-signal)
  • 3e616bf — Reset for version v0.93.2 (moiseev-signal)
  • 4c46061 — Update CDSI staging to 6d9b9649 (gram-signal)

🔒Security observations

The libsignal codebase demonstrates strong security practices as a cryptographic library. Positive indicators include: (1) Explicit SECURITY.md with responsible disclosure policy, (2) Comprehensive GitHub Actions CI/CD pipelines for automated testing and linting, (3) Rust-based implementation reducing memory safety vulnerabilities, (4) Workspace-level dependency management with audit configuration, (5) Code style enforcement (.clippy.toml, .rustfmt.toml), (6) Version pinning in Cargo.lock. No critical vulnerabilities were identified in the static file structure analysis. Minor recommendations focus on ensuring cargo-audit runs regularly in CI and maintaining up-to-date Rust versions for security patches. The absence of visible hardcoded secrets, SQL injection risks, or infrastructure misconfigurations in the provided file structure is positive. A deeper code review of actual Rust implementations, cryptographic algorithm implementations, and CI/CD workflow configurations would be needed for comprehensive security assessment.

  • Low · Cargo audit configuration exists but audit frequency unclear — .cargo/audit.toml. The repository contains .cargo/audit.toml configuration file, indicating awareness of dependency vulnerability scanning. However, from the static analysis of file structure alone, it's unclear if cargo-audit is run in CI/CD pipelines or with what frequency. The TESTING.md and CI workflow files would need review to confirm regular auditing. Fix: Ensure cargo-audit is integrated into CI/CD workflows (visible in .github/workflows) and runs on every commit. Verify that audit failures block merges.
  • Low · Rust version pinning may affect security patches — Cargo.toml [workspace.package]. The workspace specifies rust-version = '1.88' which could potentially delay security patches if a newer minor version contains critical fixes. Rust 1.88 may not receive all security updates compared to the latest stable branch. Fix: Consider using a more flexible MSRV policy or regularly update the minimum supported Rust version to ensure timely security patches. Monitor Rust security advisories.
  • Low · License is AGPL-3.0-only, potential compliance complexity — Cargo.toml [workspace.package] license field. While AGPL-3.0-only is appropriate for security-critical code, it creates strict copyleft obligations that users must understand. This is not a vulnerability but a compliance/integration consideration for downstream consumers. Fix: Ensure clear documentation about AGPL-3.0 licensing terms for all consumers of libsignal. Consider documenting license exceptions if any commercial use cases need support.

LLM-derived; treat as a starting point, not a security audit.

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/signalapp/libsignal shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live signalapp/libsignal repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/signalapp/libsignal.

What it runs against: a local clone of signalapp/libsignal — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in signalapp/libsignal | Confirms the artifact applies here, not a fork | | 2 | License is still AGPL-3.0 | Catches relicense before you depend on it | | 3 | Default branch main exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 32 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>signalapp/libsignal</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of signalapp/libsignal. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/signalapp/libsignal.git
#   cd libsignal
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of signalapp/libsignal and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "signalapp/libsignal(\\.git)?\\b" \\
  && ok "origin remote is signalapp/libsignal" \\
  || miss "origin remote is not signalapp/libsignal (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(AGPL-3\\.0)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"AGPL-3\\.0\"" package.json 2>/dev/null) \\
  && ok "license is AGPL-3.0" \\
  || miss "license drift — was AGPL-3.0 at generation time"

# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
  && ok "default branch main exists" \\
  || miss "default branch main no longer exists"

# 4. Critical files exist
test -f "Cargo.toml" \\
  && ok "Cargo.toml" \\
  || miss "missing critical file: Cargo.toml"
test -f "rust/protocol/src/lib.rs" \\
  && ok "rust/protocol/src/lib.rs" \\
  || miss "missing critical file: rust/protocol/src/lib.rs"
test -f "rust/bridge/ffi/src/lib.rs" \\
  && ok "rust/bridge/ffi/src/lib.rs" \\
  || miss "missing critical file: rust/bridge/ffi/src/lib.rs"
test -f "rust/zkgroup/src/lib.rs" \\
  && ok "rust/zkgroup/src/lib.rs" \\
  || miss "missing critical file: rust/zkgroup/src/lib.rs"
test -f "rust/crypto/src/lib.rs" \\
  && ok "rust/crypto/src/lib.rs" \\
  || miss "missing critical file: rust/crypto/src/lib.rs"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 32 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~2d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/signalapp/libsignal"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Embed this chat in your README →

Drop this iframe anywhere — the widget runs against the same live analysis cache as the main app.

<iframe
  src="https://repopilot.app/embed/signalapp/libsignal"
  width="100%" height="500"
  style="border:1px solid #d0d7de; border-radius:8px;"
  allow="microphone"
  loading="lazy"
></iframe>