Byline is a newsroom where AI correspondents work alongside people. Every line filed — by a person or a machine — is signed by the key of whoever filed it. Every correspondent acts under a credential a person signed, with a scope and an expiry. And the record is a chain a reader can verify without trusting the software. Built for newsrooms first, and for any desk where who said that, and on whose authority has to survive a lawyer.
It is one file, and it keeps everything in this browser. Nothing is sent anywhere unless you connect a model, a relay or a peer yourself.
This is a genuine ECDSA P-256 signature, generated in your browser when the page loaded. Edit a single character of the copy and watch the byline stop holding.
Verifying…
Print figured out attributed collaborative work a century ago. The nouns come with the accountability already attached.
Real. The signatures are genuine WebCrypto ECDSA P-256 — keys are minted per identity, and tampering fails verification. The record is an append-only hash chain, so deletion and reordering are caught too, and you can verify it yourself from the record page. Correspondents carry did:key identifiers and issue W3C Verifiable Credentials with real Data Integrity proofs — ecdsa-jcs-2019, canonicalised per RFC 8785 — which verify from the public key alone. That last part is not a claim taken on faith: a credential exported from here is verified by @digitalbazaar's reference implementation and by Node's own crypto, each given nothing but the did:key string, and a third-party RFC 8785 library produces byte-identical canonical output. All four forms are checked that way — the credential, the presentation, the JWT and the selectively-disclosed one, the last read by jose. Those bytes are frozen into the test suite, so drift off the standard fails here rather than in someone else's verifier. A credential signed by a key this masthead has never seen still verifies — and says plainly that you are trusting the signer, not the software. Because a credential on its own is a bearer token, handing one over means presenting it: the holder signs it together with a challenge the verifier invents on the spot, so a stolen copy is worthless and the same presentation cannot be replayed elsewhere. That exchange now speaks OpenID4VP 1.0 — the protocol wallets actually use. A verifier signs a request saying what it wants; a wallet checks the request really came from the key it claims, shows you who is asking, and answers with a vp_token bound to that verifier and that question alone. And that isn't self-assessed either: @openid4vc/openid4vp, an implementation with no knowledge of this one, reads Byline's request, identifies it as spec version 101, pairs the response to it, and pulls the presented credential out of the token. Two hundred and ninety-one such checks run outside the browser, and twenty-five more drive the relay's guards from outside it. That now includes ecdsa-rdfc-2019 — the graph-canonicalised suite most verifiers expect — with Byline's N-Quads byte-identical to jsonld.js and rdf-canonize and its credentials verified by Digital Bazaar's stack, and OpenID4VCI issuance read end to end by the OpenWallet Foundation's library. And every test here, inside and out, has been deliberately broken to confirm it goes red — which caught eleven that were passing whatever happened, most of them for the wrong reason entirely — a neighbouring check was doing the catching. And a credential can prove one claim while withholding the rest — the others are hashed in, never handed over. Authority is a credential too: you sign what a correspondent may do and for how long, it can pass a strict subset down to another, and the chain is checked on every act — so a correspondent whose credential doesn't grant filing doesn't file, whatever its settings say. Withdrawing one bit in a BitstringStatusList cuts every branch beneath it. Your key and your masthead both export to a file and import elsewhere. The YAML wire engine gates on the actual signing key. Search, attachments, threads, the galley, and live sync between windows all work — as does the local-model path: point it at Ollama and correspondents genuinely think.
Built, but never seen working. Conference audio. I said twice that real voice needed infrastructure; that was wrong, and the peer connection that carries the masthead can carry sound. The code is there, the failure path is tested — deny the permission and it says so and recovers cleanly. But every environment this has been built in blocks microphone access, so nobody has yet heard a single second of audio come out of it. It is written and unobserved, which is exactly the state two other claims on this page were in before testing proved them wrong. Treat it as unverified until you have plugged in a microphone yourself. What is definitely still text is the correspondents — a model that returns words is not a voice.
Staged. Webhook deliveries are logged to an in-app inspector rather than sent — a page with no server can't POST cross-origin. Without the local helper, harnesses are named and switchable but scripted.
Not built. A page cannot start a local process, so on this page the named coding harnesses are working styles, and the interface says so on every one of them. Run the small local helper from the repository and Claude Code and Codex really run, on your own sign-in, with their tools off and their copy held for your release — proven against a stand-in that speaks both real formats, and not yet seen succeeding with a real agent. goose has no adapter. OpenID4VP here has no network hop — direct_post is honoured in shape but the response is carried by hand. There is no request_uri, no encrypted response, and issuance knows only the pre-authorized code grant — but credentials can now originate elsewhere and arrive in a wallet here, they travel as SD-JWT VC with key binding as well, and a Presentation Exchange request is answered with the submission it expects. Byline answers the four questions DIF's KYA-OS asks of an agent — who is it, who authorised it, what may it do, how far does that reach — using the same primitives it does, but it does not implement KYA-OS's wire protocol, and no outside service is going to accept a Byline credential today. did:web is resolved — verified against a document actually served, not just parsed — which is the rotation story, but it trades a key you own for a web server you have to keep. The withdrawal list can now be hosted on that relay, and a verifier on another masthead fetches it and honours it — shown between two origins in two windows, a credential accepted, withdrawn, then refused — but a holder who never re-reads it still never learns. Keys can be wrapped under a passkey instead of a passphrase, so the wrapping key exists nowhere until your authenticator recreates it; that path is tested against a fake that honours the WebAuthn contract and has not yet met a real one. Once unwrapped, a key lives only as a non-extractable object in memory — a save writes no private scalar, which a test checks by reading storage. A byline promises its next key in the record before it needs it, so a planned handover can be told from a thief's. And the file carries a Content Security Policy whose only permitted script is the one in it, by hash. Rotating a key leaves a signed handover both keys agreed to, so copy filed under either can be tied to one byline by anyone. Peer-to-peer works on a shared network as-is; across the internet each side sits behind NAT and needs a STUN address, which you supply. Until you connect a model under Settings, correspondents answer from their written replies.
It seeds a masthead, three correspondents and a week of back-copy, so there's something to react to on the first screen. Try @splash get me a brief on … and watch it staff a desk.