TILLFORGE · CHANGELOG

TillForge, in order.

The sovereign, security-first place for your code — what we shipped, newest first. Material breaking changes are flagged in bold. Everything here speaks standard git; you never need a proprietary client to use it.

October 2026 · Data policy

  • Webhook payloads follow the workspace data policy, on first delivery and on redelivery. Credentials are always masked; other classes are kept by default and can be masked from the Data policy page. Data policy.
  • TillForge AI requests appear in the workspace's What reached AI ledger beside every other product's.

October 2026 · IaC scanning

  • Infrastructure files, judged before anything deploys. Terraform (AWS, Google Cloud, Azure, DigitalOcean and Cloudflare resources), CloudFormation (S3, security groups, RDS, EC2, CloudTrail and IAM roles) and Kubernetes manifests (workloads, services, roles and bindings) at a commit are judged by the cloud posture checks a file can answer, 59 of them today. A YAML or JSON file is judged by what it holds, not its name. Files are read on TillDev's own git servers. IaC scanning.
  • No guessing. A value from a variable, a function, another resource, or a CloudFormation parameter or import leaves the check unanswered for that resource, and the scan lists which settings it was waiting on. A setting left out reads as the provider's default for a new resource. Helm charts and other templates are listed as not read.
  • Warn or block. Unless the policy is off, every branch push, green CI build and release is scanned, and each commit gets a tilldev/iac check. Warn, the default, passes and lists findings. Block fails the check and refuses merges into protected branches while a finding at or above your bar (high by default) is active; a merge waits briefly while its head commit is being scanned. A commit whose infrastructure files are unchanged is judged again without reading them. A check turned off in the posture policies is off here too.
  • Decisions that follow the resource. Owners and admins accept a finding with a reason, and later scans accept the same check on the same resource while it keeps its address. A tillforge:allow-iac comment inside the resource accepts it in the file itself. Every decision is audited.
  • A new deploy policy check refuses a deployment whose commit has an IaC finding at your bar. It starts at warn. The supply chain map gains an Infrastructure column.
  • New findings reach your security stream as events, without the configuration. Artifact records list the active findings of their commit.
  • Dashboard: TillForge → IaC scanning (findings across default branches, policy, checks) and the repository Findings tab. API: /api/forge/repos/:repo/iac-scans, /api/forge/repos/:repo/iac-exceptions and /api/forge/iac/*, in /openapi.json. CLI 0.10.0: forge iac, which exits 1 when a finding blocks (or passes --fail-at) and 2 while the commit isn't scanned yet, and forge iac accept, exceptions, withdraw, scans, findings, policy and checks. MCP: forge_iac_scans, forge_iac_scan and forge_iac_findings.

October 2026 · Source track

  • How a commit reached the branch, recorded. Each time the default branch, or a branch a protection rule covers, moves by a push, a merged pull request, a web edit, an agent or a recovery, TillForge keeps the rule in force, who moved it, and for a merge who other than the author approved the final head. Source track.
  • Graded against the SLSA Source track. Level 2 for a protected branch with an unbroken history, Level 3 when the rule also enforces checks, signed commits, approvals or MFA to push, Level 4 for a merge approved by someone else on a rule that dismisses stale approvals. Each control records since when it has held; a force push or a recovery starts it again.
  • Signed twice over. TillSecrets grades the stored facts again, then signs source provenance and a SLSA verification summary that points at it, with the workspace key in ECDSA P-256 and ML-DSA-65. An unsigned record counts as Level 1.
  • Check a commit anywhere. tilldev forge source verify <repo> <commit> --level 3 accepts a commit prefix and works offline with saved keys.
  • A new deploy policy check, verified source. It passes when a protected branch pointed at the deployed commit at Level 3 or above and the summary is signed. It starts at warn, so existing deploys show a warning until their branches have signed records. The supply chain map gains a Source column.
  • Merges now record the commit the branch moved from in the ref log, as pushes already did.
  • Dashboard: the repository Source tab. API: /api/forge/repos/:repo/source, /api/forge/repos/:repo/source/:id and /api/forge/repos/:repo/source/:id/attestations, in /openapi.json. CLI: tilldev forge source. MCP: forge_source_records and forge_source_record.

October 2026 · Deploy gates and supply chain coverage

  • Environment approvals now hold deploys TillForge runs. A deploy to an environment with a provider starts waiting until the required number of people other than the requester approve it; on production they must be owners or admins. One rejection ends it, and a deploy with no decision lapses after 7 days. Deploys, promotions and rollbacks to environments that already require approvals now wait for them, and a new deployment is returned as waiting rather than queued. Approvals and the deploy policy.
  • A deploy policy over what the scans found. Four checks run against the commit being deployed: dependencies against your dependency policy, active secrets, code findings at your code bar, and signed provenance of a CI build. Each is off, warn or block, for production or every environment. Warn, the default, records the result and ships. Block holds the deploy while a check runs, for up to an hour, and ends it as blocked when a check fails.
  • Supply chain map. One row per repository and one column per check, read from the default branch: covered, partial or none, whether it passed, and whether a failure stops a merge or a deploy. Supply chain.
  • Deploy states waiting, blocked and rejected are set by the gate and can't be set by hand. A deployment TillForge is running no longer takes a state change by hand; its job sets it. Approvals, rejections and policy changes are in the audit trail.
  • Dashboard: TillForge → Supply chain (map and deploy policy) and approvals on each deploy in the repository Deploy tab. API: /api/forge/repos/:repo/deployments/:id/approvals, /api/forge/deploy/policy and /api/forge/supply-chain/coverage, in /openapi.json. CLI: tilldev forge deploy approve|reject|approvals|policy and tilldev forge coverage. MCP: forge_deployment_approvals, forge_deploy_policy and forge_supply_coverage; deciding stays with people.

October 2026 · Build provenance

  • Every CI build's outputs, signed. A green job that declares artifacts: gets an in-toto Statement v1 with an SLSA Provenance v1 predicate: the repository, ref, commit, workflow and trigger, the runner, the job image and the digest the runner resolved for it, and the sha256 of each output. It's wrapped in a DSSE envelope signed twice by your workspace key, with ECDSA P-256 for today's verifiers and ML-DSA-65 for after them. The private halves are made and sealed inside TillSecrets.
  • Honest levels. A signed record is SLSA Build L2. Each record lists what stands before L3: your runners are hosts your workspace runs, so TillForge can't vouch for their isolation or their measurements. A release takes the lowest level of the builds behind its assets, and an asset no build produced is L0.
  • Check a file anywhere. tilldev forge provenance verify needs both signatures and a statement naming the file's sha256, and works offline with saved keys. The P-256 signature also checks with OpenSSL.
  • Keys and re-signing. Owners and admins retire the workspace key; retired keys stay listed so older records still verify. Anyone with write access can sign a record again. Both are audited.
  • Runners now report the digest of the image a job ran in. Dashboard: TillForge → Provenance (pipelines and keys) and a provenance panel on each artifact record. API: /api/forge/provenance/pipelines, /api/forge/provenance/keys, /api/forge/provenance/keys/rotate and /api/forge/repos/:repo/artifact-records/:id/provenance, in /openapi.json. CLI 0.10.0: forge provenance, download, verify, keys and resign.

October 2026 · Code scanning

  • Every push, read for the flaws that become incidents. Fifteen rules check JavaScript and TypeScript, Python, Go, Java, Kotlin, Swift and Dart, and Android manifests, network security config and iOS plists: command and SQL injection, code built from strings, TLS and token checks switched off, file paths, URLs and redirects taken from requests, unsafe deserialisation, broken ciphers, predictable random secrets, credentials in plain app storage, cleartext traffic, open WebViews and HTML written from variables. Comments and string contents are ignored; tests, vendored, generated and minified files are skipped. Scans run on TillDev's own git servers.
  • Mapped to the frameworks you report against. Each rule names its CWE, OWASP Top 10 category and, for mobile risks, its MASVS control.
  • Warn or block. Unless the policy is off, every branch push, green CI build and release is scanned, and each commit gets a tilldev/sast check. Warn, the default, passes and lists findings. Block fails the check and refuses merges into protected branches while a finding at or above your bar (high by default) is active; a merge waits while its head commit is being scanned. After the first, a scan reads only the files changed since the last one.
  • Decisions that follow the line. Owners and admins accept a finding with a reason, and later scans accept the same rule, file and line text until that line changes. A tillforge:allow-code comment accepts a line in the code itself. Withdrawing re-grades recent commits; every decision is audited.
  • New findings reach your security stream as events, without the code. Artifact records list the active findings of their commit.
  • Dashboard: TillForge → Code scanning (findings across default branches, policy, rules) and the repository Findings tab. API: /api/forge/repos/:repo/code-scans, /api/forge/repos/:repo/code-exceptions and /api/forge/sast/*, in /openapi.json. CLI 0.10.0: forge sast, which exits 1 when a finding blocks (or passes --fail-at) and 2 while the commit isn't scanned yet, and forge sast accept, exceptions, withdraw, scans, findings, policy and rules.

October 2026 · Secrets in every file, not just every push

  • Scans of a commit's files. The push boundary sees what each push changes; a scan reads every file at a commit, so it finds secrets committed before the boundary was on or brought in some other way. Each push to the default branch, green CI build and release is scanned, and you can start one by hand. After the first, only the files changed since the last scan are read. Scans of a commit's files.
  • TillDev's own credentials are detected. The scanner now knows the prefixed credentials TillDev issues, at push and in scans: API keys, TillSecrets and agent tokens, TillForge tokens, TillAuth client secrets, refresh and SCIM tokens, and more. Each finding has a severity and names the issuing product.
  • A check, and decisions that follow the content. Each scanned commit gets a tilldev/secrets check that a branch rule can require. Owners and admins accept a finding with a reason, and later scans accept the same content wherever it appears; withdrawing re-scores recent scans. Every decision is audited.
  • Findings reach your security stream. Secrets refused or allowlisted at push, brought by a pull mirror, or found by a scan are recorded as security events, never with the value. New detections cover TillDev credentials in code, secrets in history, allowlisting and push bursts.
  • Artifact records link to the scan of their commit.
  • Dashboard: the Findings tab shows the default branch's latest scan with Scan now and Accept. API: /api/forge/repos/:repo/secret-scans, in /openapi.json. CLI 0.10.0: forge secrets, which exits 1 on an active finding and 2 while the commit isn't scanned yet, forge secrets accept and forge secrets scans.

October 2026 · Known vulnerabilities in your dependencies

  • Every SBOM is checked against OSV. TillDev keeps its own copy of the OSV advisory database, refreshed hourly, so package lists never leave TillDev to be checked. When an advisory changes, every commit using that package is checked again. Each commit gets a tilldev/sca check. Vulnerabilities.
  • Warn or block. Warn, the default, reports and passes. Block fails the check and refuses merges into protected branches while a vulnerability at or above your chosen severity has a fix, or a package is known to be malicious. A merge waits while its head commit is being checked.
  • Accepted risks expire. Owners and admins can accept one advisory, by ID or CVE, for a package, a repository or both, with a reason and for at most a year. Policy changes and exceptions are audited and re-post recent checks.
  • Reserved check names. Check contexts starting with tilldev/ can no longer be reported through the API.
  • While scanning is on, a push to any branch now makes an SBOM, not just the default branch.
  • Dashboard: findings in each repository's SBOM tab, and TillForge → Vulnerabilities. API: GET /api/forge/repos/:repo/sboms/:id/vulnerabilities, GET /api/forge/vulnerabilities, /api/forge/sca/policy and /api/forge/sca/exceptions, in /openapi.json. CLI 0.10.0: forge vulns, which exits 1 when a finding fails the policy and 2 while the commit isn't scanned yet, and forge sca policy, exceptions, except and revoke.

October 2026 · SBOMs: every dependency of every build

  • An SBOM for each build, release and default-branch push. TillForge reads the lockfiles committed at that commit, straight from the repository, and lists every package with its version, package URL, and the licence and checksum where the lockfile records them. A build's artifact record points at its SBOM. SBOMs.
  • Twelve ecosystems. npm, pnpm, Yarn and Bun; Poetry, uv, PDM, Pipenv and pinned requirements files; Go modules; Cargo; Bundler; Composer; Gradle lockfiles; NuGet; SwiftPM; CocoaPods; pub; Mix. A lockfile that can't be read, such as the binary bun.lockb, is listed with the reason and the SBOM is marked partial.
  • CycloneDX 1.6 download. The same bytes every time, with their sha256 recorded and checked before the file is served.
  • Which repositories use a package? Search every SBOM you can read by name, ecosystem and version, and see whether each repository's default branch still has it. Python names match however they're written.
  • Dashboard: an SBOM tab on each repository, and Dependencies in TillForge. API: GET and POST /api/forge/repos/:repo/sboms, /sboms/:id, /sboms/:id/components, /sboms/:id/cyclonedx and GET /api/forge/dependencies, in /openapi.json. A workspace can make 30 SBOMs by hand an hour. In CLI 0.10.0: forge sbom (with --out to save a hash-checked file and --packages to list them), forge sboms and forge deps <package>, which exits 1 when no repository uses it.

October 2026 · Artifact records: trace a file to the build that made it

  • Every build leaves a record. A successful CI job records its commit, ref, runner and the sha256 of each file it lists under artifacts: in .tillforge/ci.yml. The runner hashes them on its own side after the job's container exits, so a step can't report a checksum of its choosing. Artifact records.
  • Outputs are checked, not trusted. A listed path that matches no file, passes through a symlink, or names something outside the workspace fails the job with that reason. Up to 50 files a job, 8 GiB each and 16 GiB in total.
  • Releases link to their builds. A release records each asset that carries a sha256 and links to the CI builds whose outputs match, whether the build or the release came first. Adding or removing an asset updates the record.
  • Records outlive what they describe. Deleting a job, a release or a repository keeps its records.
  • Breaking: a job that lists artifacts needs an upgraded runner. An older runner claiming one fails it with a reason instead of passing it with nothing recorded. Upgrade the runner and rerun the job.
  • Dashboard: an Artifacts tab on each repository, with a file chooser that hashes in the browser and never uploads. API: GET /api/forge/repos/:repo/artifact-records (filter by commit, digest or source), GET /api/forge/repos/:repo/artifact-records/:id, GET /api/forge/artifact-records?digest= across the repositories you can read, and artifacts on a CI job's config, in /openapi.json. In CLI 0.10.0: forge artifacts, forge artifacts show and forge artifacts verify <file>, which sends only the digest and exits 1 when no recorded build produced the file.

September 2026 · Choose the region your repositories are stored in

  • Data region. An owner picks the region, from those TillDev runs git servers in, where the organization's repositories are stored. Repositories created from then on keep their files, history and LFS objects on git servers there, and every clone, fetch and push is served there. Names, settings, permissions, pull requests, issues, CI logs and release downloads are held centrally. Changing the region moves where new repositories go; existing ones stay where they are. Audited. Data region.
  • Each region has its own git host. The repository page, the CLI and the API give each repository's clone URLs on its region's host. Cloning or pushing through another region's host sends git on to the right one, for anyone who may reach the repository. tilldev forge setup-git now sets git up for every TillForge host.
  • Keys go only where your repositories are. A git server is given an organization's repository key only if it holds that organization's repositories or serves its region, and only from that server's own addresses. The copy of access rules a git server keeps for outages covers only what it holds.
  • Runners by region. A runner registered with a region takes jobs only for repositories stored there.
  • Forks stay with their source. Forking a repository stored in a region other than your organization's is refused.
  • Encryption at rest now shows each region's storage, and an erase that a git server hasn't confirmed yet names its region.
  • Dashboard: TillForge → Data region; the region on repository tiles, the repository page and runners; Encryption lists each region. API: GET and PUT /api/forge/region, GET /api/forge/hosts, region and region_label on repositories, region on runners, and regions and erase_waiting on encryption, in /openapi.json. In CLI 0.8.0: forge region and forge region set, forge ci runners register --region, a REGION column on repositories and runners, and per-region lines in forge encryption.

September 2026 · Webhook deliveries can't be replayed

  • Webhook deliveries can't be replayed. Each delivery now carries X-TillForge-Webhook-Signature: t=<unix>,v1=<hex>, an HMAC-SHA256 of the timestamp and the raw body, the same scheme as TillAuth webhooks. Refuse a timestamp more than five minutes off and a recorded delivery is useless to anyone who captured it. Before, the signature covered the body alone, so a captured delivery verified forever. X-TillForge-Signature is still sent for existing receivers; move to the new header. Verify.
  • Every delivery says which one it is. The body carries delivery_id, the same on every retry and in X-TillForge-Delivery, and attempt, so a receiver can skip one it has handled.
  • Every new webhook is signed. Leave out the secret and one is made and shown once. A webhook made without one before is marked unsigned; give it a secret from the Webhooks screen or the CLI.
  • Fixed: failed deliveries were retried less than intended. A delivery is now tried six times, at once and then after 1 minute, 5 minutes, 25 minutes, 2 hours and 10 hours; the first retry used to wait 5 minutes and the last never happened.
  • Dashboard: Webhooks shows signed or unsigned, with Add one and Rotate secret. API: POST /api/forge/webhooks/:id/secret, signed on a webhook and secret when one is made, in /openapi.json. In CLI 0.8.0: forge webhook secret, a SIGNED column, and add prints a made secret.

September 2026 · Mirrors reach only the hosts you name

  • Name the hosts your mirrors may reach. An owner or admin can list the only hosts this workspace's mirrors connect to, such as github.com or *.git.example.com (its subdomains). A mirror to any other host is refused when it's set up and at every sync, including mirrors that already exist, and setting the hosts lists the mirrors now outside them. With none set, mirrors reach any public https host, as before. Audited. Security.
  • Fixed: a mirror refused at sync time left no trace. A sync refused because its address was no longer public was skipped silently; it's now in the audit log as a failed sync, once an hour while it keeps failing.
  • Dashboard: the Egress page (formerly AI egress) sets the mirror hosts. API: GET and PUT /api/forge/mirror-hosts, and mirror_hosts on a refused mirror, in /openapi.json. In CLI 0.8.0: forge mirror-hosts, set and clear.

September 2026 · Allowlisting a refused secret lets it through

  • Allowlisting a refused secret now lets it through. When an owner or admin allowlists a finding the secret scan refused, the same rule, file content and line pass the next time they're pushed, committed in the dashboard or through the API, or written by an agent. Changed content is scanned again. Before, the allowlist was recorded but the next push was still refused, so the only way through was an inline marker. The push that lands is recorded as allowlisted by that admin, with their reason. Secrets.
  • An allowlist can be withdrawn before the content lands, and the content is refused again. Audited.
  • Breaking: an allowlisted refusal stays rejected, with allowlisted_by set, until the push that lands records it as allowlisted. An allowlisted finding is already in history and can't be allowlisted again (409). A finding allowlisted before this change stays as a record; if the push is still refused, allowlist the new finding.
  • Fixed: findings allowlisted with a marker didn't show in the Findings tab. They're listed now, with who let them through and why.
  • Dashboard: the Findings tab shows allowlisted refusals, with Withdraw, and what was allowlisted into history. API: DELETE /api/forge/repos/:repo/findings/:id/allowlist, and commit_sha on a finding now names the blob the secret is in, in /openapi.json. In CLI 0.8.0: forge allowlist --revoke, and forge findings shows rejected · allowlisted.

September 2026 · Mirrors are checked where they connect, and scanned

  • A mirror can't be turned inward. The git server now connects a mirror only to public addresses, checked on the address it actually connects to, so a name that later resolves to a private, loopback or cloud-metadata address is refused. Mirrors use https only and never follow a redirect. Before, the address was checked only when the mirror was set up.
  • A pull mirror's history is scanned. Each sync checks what it brings for malformed objects and scans it for secrets, including your TillSecrets values, before the branches move. The upstream already has that history, so a secret can't be refused: it shows up as a mirrored finding to rotate, a private SSH key among them is revoked in every workspace, and a TillSecrets value raises a leak. Mark one handled with a reason once it's rotated. Secrets.
  • Breaking: a pull mirror sync fails, leaving the branches where they were, when its URL resolves to a non-public address, it redirects, it isn't https, its history has malformed objects, or its secrets can't be scanned and recorded.
  • Dashboard: the Findings tab lists mirrored secrets and counts them until they're marked handled. API: mirrored in a finding's action, in /openapi.json. In CLI 0.8.0: forge findings shows mirrored and mirrored, handled, and forge allowlist marks a mirrored finding handled.

September 2026 · Leaked SSH keys are refused everywhere

  • A private SSH key that lands in a repository is revoked everywhere. When the secret scan flags a private SSH key and it is allowlisted into history, anyone who can read the repository holds it. Every registration of that key is now revoked in every workspace, it can't be added again, and its commit signatures stop counting as Verified. The git server proves it holds the key before anything is revoked; a push the scan refused revokes nothing. The finding names the key. Leaked keys.
  • Published keys are refused. Keys whose private half ships with tools, such as Vagrant's insecure keys, can't be registered for SSH or commit signing.
  • Breaking: RSA keys under 2048 bits are refused for SSH and commit signing. One already registered shows as refused · too weak, stops working over SSH and its signatures stop counting as Verified. Make a new key with ssh-keygen -t ed25519.
  • Breaking: registered Vagrant insecure keys are revoked.
  • Fixed: a key registered in two workspaces worked in only one of them, and someone who registered your public key in their workspace could stop it working in yours. Each registration now governs only its own workspace.
  • Dashboard: SSH keys and deploy keys show revoked · private key leaked and refused · too weak; signing keys show not trusted; a repository's Findings list private SSH keys in history. API: revoked_reason and weakness on keys, refused on signing keys, ssh_key on findings, and 422 for a leaked key, in /openapi.json. In CLI 0.8.0: forge keys ls and forge keys-account ls show the state, forge findings shows the key, and forge signing-key ls marks keys that aren't trusted.

September 2026 · Big files go to Git LFS

  • Big files go to Git LFS. Every repository has a file size limit, 100 MiB unless an admin changes it. A push that adds a file over it is refused with each file's size and the commands that move it to Git LFS; a new file over half the limit gets a warning. Merges (whatever the strategy), browser edits and API commits hold to the same limit. Files already in a repository aren't affected. File size.
  • Git LFS is documented. Every repository takes Git LFS with the same token as git over HTTPS; each object can be up to 2 GiB. Git LFS.
  • Malformed objects are refused. Every object a push brings is checked before it is stored, so a crafted tree or a submodule name that points outside the repository can't reach the people who clone it. Defects common in old imported histories, such as a malformed date, only warn.
  • Breaking: a push that adds a file over 100 MiB is refused, including the first push of an imported history. Move the file to Git LFS, or have an admin raise or turn off the limit for that repository.
  • Fixed: pushes over SSH weren't held to the 2 GiB push size cap that pushes over HTTPS were.
  • Dashboard: a repository's Settings → File size limit. API: max_file_mb on repositories, and file_limit and large_files on a refused merge or commit, in /openapi.json. In CLI 0.8.0: forge repos update --max-file-mb, and a refused merge prints the Git LFS commands.

September 2026 · Commits name the person who pushed them

  • Commit identity is checked at push. The committer of every new commit and the tagger of every new tag must be the person pushing, so no one can push work under a colleague's name. Rebased, cherry-picked and patched commits keep their author. A repository can also require the author to be the pusher, or turn the check off. The first push into an empty repository is exempt so history can be imported, and a refused push lists the commits and how to fix them. Commit identity.
  • Commit emails. Your account email always counts. Add another address and enter the code TillForge emails to it; it then counts for pushes and for signed commits. An address another person in the workspace uses can't be added.
  • SSH keys belong to someone. Every member can add their own SSH keys. A person's key reaches only the repositories they can, pushes as them, and stops working when they leave the workspace. Owners and admins add machine keys for automation; like deploy keys and deploy tokens, they belong to no person, so their commits can't name one. SSH keys.
  • Breaking: commit identity is on for every repository. A push whose new commits name someone else as committer is refused. Add your other addresses as commit emails, or have an admin turn the check off for that repository.
  • Breaking: existing workspace-wide SSH keys now belong to the admin who added them, reach only what that admin can, and push as them. If an admin added a key for a teammate, the teammate should add their own; a key for automation should be added again as a machine key. Keys with no known owner become machine keys.
  • Dashboard: a repository's Settings → Commit identity, Signing keys → Commit emails, and who each SSH key belongs to. API: identity_check on repositories, machine, owner and mine on SSH keys, and /api/forge/commit-emails, in /openapi.json. In CLI 0.8.0: forge repos update --identity, forge keys-account add --machine and forge commit-email.

September 2026 · Post-quantum signed commits

  • Hybrid signing keys. tilldev forge signing-key new --git --global --sign-all makes an ML-DSA-65 + Ed25519 key on your machine, registers it and has git sign every commit and tag with it. Both signatures must verify, so a signature holds while either algorithm does. git works as usual through a small stand-in for ssh-keygen; a signature is about 7 KB. Signed commits.
  • Require them on a branch. A branch rule can accept hybrid signatures only: Hybrid post-quantum in the rule editor, or --signed-with hybrid. The editor and policy ls warn while no hybrid key is registered.
  • TillForge signs what it writes. Merges, squashes, rebases and browser and agent edits are signed with TillForge's own hybrid key and show Verified · TillForge.
  • Pull requests are checked commit by commit. Before a merge, every commit the pull request brings must meet the target branch's signature rule, whatever the strategy. A refused merge lists them, in the dashboard and the CLI.
  • Tags show their verdict next to commits: Verified, Unverified or Unsigned, with a PQ mark for hybrid signatures.
  • Breaking: Require signed commits now needs a key registered to the commit's author or committer. It used to accept any signature, even one that didn't verify. PGP signatures are refused on these branches, since TillForge can't verify them; register an SSH or hybrid key instead.
  • Fixed: merges, browser edits and agent commits skipped the signed-commit rule. They wrote unsigned commits to branches that required signatures, and a pull request's own commits were never checked.
  • Fixed: signed commits were refused on branches that required them, because the git server read every signature as missing.
  • API: signature_suite on branch policies, hybrid_signing_keys in their responses, suite, key_type and server on signature verdicts, GET /api/forge/repos/{repo}/tags/signature, and signature_problems on a refused merge or commit, in /openapi.json. In CLI 0.8.0: forge signing-key new and git, and forge policy set --signed-with.

September 2026 · Encryption at rest per organization

  • Each organization’s repositories are encrypted on disk under a key of its own. Linux filesystem encryption (fscrypt v2): AES-256-XTS for contents and AES-256-CTS for file names. It covers repositories, LFS objects, deleted repositories waiting to be purged and pushes while they are received. Existing repositories are encrypted in place. Encryption at rest.
  • The key stays with TillDev. It is sealed with AES-256-GCM under the organization’s data key and handed only to the git server, which must present its secret from an allowed address. Every hand-over is in the TillForge audit log as repo_key.release, with its reason.
  • Backups are sealed with the same key before they leave the git server.
  • Erase every repository. An owner can destroy the key and delete every repository, with its pull requests, issues, settings and LFS objects; backups can no longer be opened. It needs the organization’s slug typed out and a new approval, repos.erase. Forks in other organizations stay.
  • After the git server’s machine restarts it fetches the keys again. Until it can, repositories answer 503, locked, instead of a false not-found; this now includes a dashboard outage that spans such a restart.
  • Dashboard: TillForge → Encryption. API: GET /api/forge/encryption and POST /api/forge/encryption/erase, in /openapi.json. In CLI 0.8.0: forge encryption and forge encryption erase --confirm <org-slug>.

September 2026 · Through a dashboard outage

The git server used to lean on the dashboard for every decision. It now carries on without it.

  • Clones and pushes keep working for up to 72 hours if the dashboard can’t be reached, on a copy of access and branch protection signed with Ed25519 and ML-DSA-65 and refreshed on every change. See when the dashboard is down.
  • A push during an outage is checked against branch protection or refused. It used to fall back to guarding only the default branch. With no usable signed copy, the push is now refused.
  • A push that lands during an outage keeps its place in the ref log, and its CI, webhooks, deployments and secret findings arrive once the dashboard is back, stamped with the time of the push.
  • Fixed: repository grants from the Access Centre were not applied over git. A member limited to some repositories could clone other internal repositories with a token. They now reach only the repositories they were granted, plus public ones read-only.
  • Fixed: SSH keys of a suspended workspace kept working over SSH. They are refused at sign-in now, like its tokens.
  • CI secret names the runner reserves (GODEBUG, GOGC, GOMAXPROCS, GOMEMLIMIT, GOTRACEBACK) are refused when you save them instead of failing the job.

September 2026 · Faster clones

Clones of large repositories were slow enough to time out on distant or lossy connections.

  • A clone starts sending at once. Data used to be held back until the whole pack was ready, and the connection then restarted cold. It now streams from the first byte, and repositories are repacked in the background after pushes so a clone sends stored data instead of recompressing history.
  • Partial and sparse clones. --filter=blob:none, blob:limit=<size> and tree:0 now work over HTTPS and SSH, with --sparse for the directories you need. See large repositories.
  • Fewer round trips before a clone begins, over HTTPS and SSH.
  • Fixed: objects left behind by a force-push or a deleted branch could be fetched by hash by anyone with read access, over HTTPS or over SSH with git’s newer protocol. Only objects reachable from a branch or tag are served now; the others stay recoverable by restoring the branch.

September 2026 · From a crash to the change behind it

Which change broke the release, who should look at it, and a review loop that stays in the editor.

  • Suspect changes. The new Crashes tab lists the releases that shipped this repository’s commits. Pick one to rank the pull requests and commits since the previous release by how closely their changed files match the stacks of its new crashes. Also tilldev forge correlation <repo> --release <version>. See which change caused which crash.
  • Crash owners. Link the repository to a TillPulse project in Settings and each new crash group notifies whoever last changed the file where it crashed.
  • Review in VS Code. Open a pull request’s files as diffs, comment on lines, and approve or request changes from the editor. Lines in open crash stacks show “crashed N× in prod”.
  • Comments follow their line through later pushes and rebases, and are marked outdated when that line changes.
  • Fixed: same-repository pull requests ignored pushes made after they were opened. The diff went stale, checks did not re-run, and approvals given after a push never counted toward the merge gate. Pull requests now track their branch.
  • Names instead of ids for reviewers, comment authors, issue authors and assignees, in the dashboard, CLI and API. tilldev forge reflog <repo> --ref <branch> filters the history to one branch and shows who made each change.
  • CI secrets and service containers. Bind a TillSecrets environment to a repository and list the keys a job needs; declare services: such as a database next to a job. Breaking: jobs that use secrets, and every deploy, run only on runners registered with --secrets, and jobs no longer run as root by default. See CI.
  • Fixed: files that would not open. A file that could not be read showed an empty panel, or the previously opened file under the new name. In the web editor the error text became an unsaved change that could be committed. Both now show the error with a retry, and nothing unread can be committed. Switching branch in the editor re-reads open files from the new branch.
  • ✎ Editor on a file in the Code tab opens that file in the web editor. Submodules are marked as such instead of failing to open.

July 2026 · Events, search, and notifications

The forge now tells the right systems — and the right people — when something happens.

  • Webhooks & events. Subscribe an endpoint to push, pull_request, issue, release, deployment, and check events. Every delivery is HMAC-signed so you can verify it, and the full delivery log is inspectable — see Events & webhooks.
  • Code search. Literal, line-numbered search across a repo at any revision, from the CLI or the Code tab — no index to build, no query language to learn.
  • Notifications. A personal inbox: you’re notified when your pull request or issue is reviewed, commented on, or merged, deep-linked to the thread.

July 2026 · The ship pipeline

From a reviewed commit to a released, deployed build — with a gate before production.

  • Releases & builds. Cut a tagged release with a changelog generated from the commits since your last tag, then attach a build per platform — Linux, macOS, Windows, Android, iOS, web, or source — each with a published sha256.
  • Deployments. Ship a commit to an environment; preview freely, and require approvals on the environments that matter before anything goes to production. Every deploy is pinned to its commit for crash correlation.
  • Line-level diff. Compare any two revisions and read a real unified diff — colored hunks, per-file — on the web and in a pull request’s review room.
  • forge clone + git credential helper. One command clones with the right remote, and the credential helper feeds your token to git without it ever touching a URL or your shell history.

July 2026 · Collaboration

  • Pull requests, in full. A review room with a merge gate, review verdicts, and inline comment threads over the changed files — see Pull requests.
  • Issues with comments and labels, and collaborators — grant people access to a repo with a role.
  • Account SSH keys and shown-once tfp_ access tokens, scoped and expiring by policy — see Access & tokens.

July 2026 · TillForge — the sovereign forge

The foundation: hosting your code without giving up control of it. Everything speaks standard git.

  • Standard git, zero plugin. Clone and push over HTTPS with a token or over SSH with a registered key, from any editor — see Repositories.
  • Reject at the push boundary. Secrets are refused before they enter history — a rejected push, not an after-the-fact alert. Branch protection, author checks, and the same secret guard apply identically over HTTPS and SSH — see Branch protection.
  • One-click recovery. A protected branch keeps a recovery trail, so a bad force-push or a deleted branch is a click to restore, not a support ticket.
  • Commit graph, code browse, history, and blame — read a repo without cloning it.
  • AI egress governance. Code sent to an AI is default-deny, redacted, and audited — you authorize what leaves, and it’s on the record. Air-gapped operation is a supported mode — see Security posture.
  • A full tilldev forge CLI, an MCP server, and a VS Code extension — the forge from your terminal, your agent, and your editor.

New here? Start with the quickstart or the product overview. Looking for another product? See the TillAuth and TillShield changelogs, or the full TillDev shipping log.