更新日志
Beacon 的更新日志只有英文版,以下照录;它也是 GitHub 发布说明的来源。版本号遵循语义化版本;预发布版本(-rc.N)列在它所通向的版本下面。
Unreleased
0.3.0
rc.10 (2026-11-02)
- The console's stylesheets and scripts are linked with Beacon's version in the URL, so a cache in front (a CDN, a browser) never serves the previous release's styling after an upgrade.
rc.9 (2026-11-02)
- The console draws with
@openlinkos/ui0.7.0, which carries the Beacon brand (signal orange, the mark); the provisional stylesheet is gone. The docs site uses the theme 0.7.0 with the same brand.
rc.8 (2026-11-02)
- A
SIGHUPthat arrives while the service is still starting no longer ends it: the signal is taken from the first instant and acted on once the service is up. A deployment that reloads right after starting the service used to kill it, the more so as start-up grew with the console.
rc.7 (2026-11-02)
DELETE /api/v1/tokens/{name}and the MCP toolrevoke_token(machines:write): revoke a token that reaches machines, the pause switch for one agent, as the console does; machines' and services' tokens stay withlinkos-beacon token revokeon the host. New error codestoken.not_found,token.not_revocable.- What the first drill showed missing (
docs/agents.md,docs/catalog.md): the agent woken byHeartbeatStalefound the machine only in the heartbeat's description, did not see the session that broke it, and was told of the end while its first run was still writing.- Heartbeats name their machine: a heartbeat in the catalogue takes
machine, a machine as the SSH channel names it. The evidence and the timeline for an alert with aheartbeatlabel then haveheartbeats(the catalogue entry, whether the machine is enrolled, the last success from VictoriaMetrics, a hint on reaching it) and count that machine among the alert's machines, so its sessions and changes are listed; the firing hook's hint names it. A put through the API or MCP refuses a machine that is not enrolled (config.invalid), unless the heartbeat named it already; an import or a revert takes one and warns (warningson the change, the log,config import's output), andcheck-configlists such heartbeats without failing.linkos_heartbeat_max_age_secondshas amachinelabel when one is set; the rules aggregate it away.config exportwrites it. - Before the alert: every change and session in the evidence and the timeline has a
phase,beforethe alert started,duringorafterit resolved, and the sessions on the alert's machines before it are kept first when there are many. A shell session has its last 20 commands with their exit statuses (shell_commands), and the timeline has each as acommandevent, and a heartbeat's last success as aheartbeatevent. - The resolved call waits: a hook's call for a resolved group goes out
resolved_afterlater (1mby default,0at once, at most5m), so the first run's closing note is on the timeline; a group that fires again meanwhile drops it. Theresolvedpayload hasfiring_call(delivery,at,status,recent), and when the firing call is under ten minutes old the hint says the earlier run may still be finishing its notes. Agent calls havedue.
- Heartbeats name their machine: a heartbeat in the catalogue takes
- The site, beacon.openlinkos.com (
docs/): Beacon's home page and documentation, in English and Simplified Chinese, on the shared OpenLinkOS theme. The home page shows the three pillars and how Beacon fits; the guide keeps its pages (docs/goals.mdand the rest stay where they were) and gains an architecture page, a reference for the REST API (routes, scopes, error codes) and the MCP tools, a page on the sources Beacon takes in, and this changelog. Headings take GitHub's ids, so links to them work on GitHub and on the site alike.- The build fails when a Chinese page falls behind its English page, or when the reference misses a route, an error code, a scope or an MCP tool that the code has. CI builds the site on every pull request; the
siteworkflow publishes the imageghcr.io/openlinkos/beacon-site(nginx, port 8080,linux/amd64andlinux/arm64) frommain, tagged<UTC time>-<commit>. - A code of conduct (Contributor Covenant 2.1), issue forms, a pull request template, Dependabot for the site, and how to work on the site in
CONTRIBUTING.md.
- The build fails when a Chinese page falls behind its English page, or when the reference misses a route, an error code, a scope or an MCP tool that the code has. CI builds the site on every pull request; the
- The console (
docs/pages.md): Beacon's own workbench, served bylinkos-beaconat/on port 17001 beside the API, on the OpenLinkOS design system@openlinkos/ui0.6.1 (its workbench shell, vendored underinternal/web/static/olwithscripts/update-ui.sh), so the family looks alike. One place for people to look at everything:- the overview (firing alerts by severity, probe locations expected and reporting, machines, the SSH channel, agents woken and sessions today, the configuration's and Beacon's versions, each linking to its list); alerts, sessions, agent calls, the audit log and change events as lists with facets and search, 50 to a page; machines with the pause switch, and each machine's sessions and commands; tokens with their scopes, machines and SSH keys; the configuration read-only, with its history and each version's diff. The alert's and the session's pages move onto the same shell; signed links and bearer tokens keep opening them without signing in, view-only.
- No login system of Beacon's own:
/sign-intakes a Beacon token (status:readat least) and keeps a 12-hour session bound to it, in anHttpOnly,Secure,SameSite=Strictcookie; revoking the token ends it, and its scopes are what the console may do. Failed sign-ins count against the API's limit. The console needs HTTPS (orlocalhost). - Forms, each with a CSRF secret and the scope of the matching API route, done as the token with
viaconsole, audited and echoed to the chat: acknowledge with a note, silence for 1, 4 or 24 hours, add a note (alerts:write); pause and resume agents' access, revoke a token that reaches machines (machines:write; other tokens stay with the admin socket); revert a configuration change (config:write). - One page for every screen, adapted by CSS alone (a full sidebar from 1200px, a rail from 860px, a sheet below, lists restacked at phone widths); in Chinese or English; no inline script or style. The pages'
Content-Security-Policynow also allows fonts and forms from Beacon itself. Beacon's accent (data-brand="beacon") is provisional until the design system ships it.
rc.6 (2026-11-02)
- Tokens are 56 characters again, as before rc.5: the secret field that seemed to cut them did not.
rc.5 (2026-11-02)
- Tokens are 32 characters (
lbt_and 17 random bytes in base32, 136 bits), down from 56: bot platforms' secret fields cut long values. Tokens issued before keep working.
rc.4 (2026-11-02)
- Hooks for receivers with a secret of their own (
docs/agents.md): akind: webhookhook takesheaders_file, a file ofName: valuelines sent with every call (Authorization: Bearer …,X-Webhook-Secret: …), for bot platforms that check their own secret rather than Beacon's signature. One ofsecret_fileandheaders_fileis required; with both, the call is signed and carries the headers.X-Beacon-EventandX-Beacon-Deliveryare always sent.
rc.3 (2026-11-02)
- The agent on call:
linkos-oncall(docs/agents.md, "Running an agent when woken"): a reference harness, a third binary in the releases, that runs an agent program when a hook wakes it. It takes the signed webhook, checks the signature, refuses replays and deliveries older than 15 minutes, remembers each delivery for a day, answers at once, and starts the program named with-run(-run-resolvedfor resolved events) with the payload on its standard input and the alert inBEACON_*variables.-concurrencyprograms run at once, up to 32 wait, beyond that Beacon is told to try later; each run's output is kept under-log-dirfor-keep; a run is killed with its whole process group after-timeout; stopping waits for the runs in progress.contrib/oncall: wrappers for Claude Code (headless, Beacon's MCP server with the token read from a file at each connection, Beacon's tools and nothing else, nobody to ask) and Codex (codex exec), the one-page prompt for the woken agent, and a systemd unit with its own user and a read-only system.contrib/github/oncall.yml: the same for a hook ofkind: github, through the Claude Code GitHub Action. Beacon still calls no model: the harness decides nothing, the agent does, and Beacon records it.
- Probe again, now (
docs/agents.md):POST /api/v1/probe-nowand the MCP toolprobe_now(alerts:write) have every location that probes a target probe it again at once and return each location's result (ok, reason, duration, HTTP status, attempts, certificate expiry, when), the locations that did not answer in time and a one-line summary; byalert_id,target(with amodule) orservice, waiting 45 seconds by default and 90 at most. The probes push the fresh samples as in their cycle, so alerts resolve sooner. Limits: one request per target every 15 seconds and three in flight per token (probe.busy); an unknown target isprobe.not_found; without a gateway,probe.unavailable. Audited (probe_now) and echoed to the chat.- The probe protocol gains
GET /api/v1/agent/requests?wait=25s(a long-poll) andPOST /api/v1/agent/requests/{id}on the gateway.linkos-probe agentpolls beside its cycle; against an older gateway it asks again in an hour. Older probes keep working and show up as missing. - Metrics
linkos_probe_now_requests_total,linkos_probe_now_answers_total{location},linkos_probe_now_missing_total{location}andlinkos_probe_now_requests_open.
- The probe protocol gains
- People's pages (
docs/pages.md): from the card, one link opens the alert's page, and from there each session's replay. Served bylinkos-beaconbeside the API atpublic_url; no login system.GET /alerts/{id}: the alert, each location's latest result and reason, related alerts, the agents woken and whether the SSH channel is paused, the sessions on its machines with their commands and exit statuses (each with a Replay link), notes, changes, labels, and the timeline.GET /sessions/{id}: who, where, when, how long, the commands, and the recording replayed in the page (asciinema-player 3.17.0, embedded; asciicast v3). In the configured language, light and dark, laid out for a phone; a strictContent-Security-Policy,noindex, no referrer, nothing fetched from elsewhere.- Signed links:
?s=<expiry>.<HMAC-SHA256>under a key Beacon makes at first start and keeps in its database; valid forpages.link_ttl(30 days by default). A bearer token withstatus:read(alerts) orsessions:read/machines:ssh(sessions) opens a page too; anything else is 404. Anyone holding a link sees that page, so the chat the links go to must be private. - The links are on the card (a Timeline button; an Agents block with the hooks woken and "N sessions on M machines, K commands"), in the chat echoes of agents' sessions (a Replay link each), and in the API and MCP answers (
pageon alerts and sessions,links.pagein the evidence,urlon a timeline's session events), so an agent can hand a person a link.
- Machines behind NAT (
docs/ssh.md, Machines behind NAT): a machine Beacon cannot connect to connects out to the channel itself with plain OpenSSH (ssh -N -R 0:localhost:22 NAME@beacon:17002, a dedicated key, a systemd unit), and Beacon reaches its sshd through that connection; nothing is installed on the machine. Beacon tells a machine's connection from an agent's by the key: the connector key is registered on the machine, an agent's on its token. Such a connection may only ask for its one forward and keep alive; one per machine, the newest wins; Beacon binds no port and connects only to the address the machine itself forwarded, with the pinned host key and a certificate as always (itssource-addressalso allows127.0.0.1/32and::1/128for such a machine, since its sshd sees the connection come from itself).- CLI:
machine add NAME connector -key KEY|@FILE [-host-key KEY|@FILE]prints the whole machine-side setup (CA, account,known_hostsline for the channel, the connector's user and key, the unit);machine connector NAME -key …sets or changes the key;machine listshows whether it is connected and since when. The host key is given with-host-keyor learned the first time the machine connects, audited (machine_host_key) and echoed to the chat. add_machineandPOST /api/v1/machinestakeaddress: connector,connector_keyandhost_keyand return the setup asconnector; newset_machine_connectorandPUT /api/v1/machines/{name}/connector; machines carryconnector,connected,connected_since. A machine whose connector is not connected fails fast with the new error codemachine.disconnected.- Gauges
linkos_beacon_ssh_connectors(connected) andlinkos_beacon_ssh_connector_machines(added); connects, disconnects and replacements are logged; key changes are audited (machine_connector).
- CLI:
- Agents' credentials and safe configuration (goals 6 and 7;
docs/agents.md,docs/catalog.md): tokens renew themselves, andconfig:writeis safe to give an agent.- Tokens renew themselves:
POST /api/v1/token/renewand the MCP toolrenew_token(any scope) give the caller's token a new secret with the same name, scopes, subject, machines and SSH keys, expiring its lifetime from now; the old secret works for ten more minutes, so a client swaps its token file without a race. At most once every 24 hours (token.too_soon, 429); enrolled machines' tokens cannot (token.not_renewable, 403),enroll -rotatereplaces them. Audited (token_renew) and echoed to the chat.GET /api/v1/tokenandwhoamidescribe the caller's token: name, scopes, machines, expiry, lifetime, whether and when it may renew. Tokens keep their lifetime (token listshows it and the last renewal); tokens from before getexpires - created. SSH sign-in is by key and is untouched by a renewal. - Probe modules read files from one directory:
password_filenames a file in the probe's secrets directory (linkos-probe -secrets-dir,/etc/linkos-agent/secretsby default), never a path. The probe refuses a path before reading anything (probe_failure_info{reason="config"}), and Beacon refuses it withconfig.invalidwhen a module is put or imported (API, MCP, CLI, files). Transition: a module file already in the database with such a value is still served, with the problem logged, until the module is put right; probes from before this release read the name relative to their working directory, so upgrade them before adding a module withpassword_file. if_versiononPUTandDELETEunder/api/v1/configand onput_configanddelete_config: the version the caller last saw; when a later one is in force the change is refused withconfig.conflict, naming it.- The gateway takes at most 60 change events a minute per token; the rest get
429withchanges.too_many, counted inlinkos_gateway_changes_limited_total{token}. - MCP has two more tools (
whoami,renew_token); new error codestoken.too_soon,token.not_renewable,changes.too_many.
- Tokens renew themselves:
- Release for others: a reference deployment under
deploy/(Compose withlinkos-beacon, VictoriaMetrics, vmalert and Caddy, images pinned by digest;install.shmakes the secrets, puts your host names in, validates every file with its own image and starts it; generic alert rules with unit tests and a runbook per alert; the probe's systemd unit and installer),docs/install.md("Up in 30 minutes"),CONTRIBUTING.mdandSECURITY.md. Adeployworkflow validates the deployment on every change.- CLI:
silence create -matchers 'alertname=X,service=Y' -duration 4h -comment TEXT(or-alert GROUP_ID),silence list,silence expire ID, through the admin socket and the bridge's own methods: audited ascliand echoed to the alert chat like a silence made through the API or MCP; a firing group every alert of which matches is marked silenced and acknowledged.
- CLI:
rc.2 (2026-11-02)
- Waking agents, and evidence (
docs/agents.md): a new alert can wake an agent, which then finds what it needs in one call. Beacon calls no model.agents:in the configuration: hooks called when a new alert group is first notified (and, withresolved: true, when it resolves), chosen by severity and aserviceregular expression.kind: webhookPOSTs a compact JSON payload signed with HMAC-SHA256 (X-Beacon-Signature: sha256=…, the secret fromsecret_file);kind: githubdispatches a workflow with the inputsalertandevent. Calls never hold up alert delivery, are retried with backoff (five tries in about five minutes), and their outcome is kept on the group (agentsin the API), in the audit log (wake_agent), on the card and in the chat.public_urlis required with agents.- Evidence:
GET /api/v1/alerts/{id}/evidenceand the MCP toolget_evidence: per probe location the result, since when it fails and why, duration, HTTP status, attempts and certificate expiry from VictoriaMetrics; the alerts firing in the same failure domain; the change events around it; what was done (acknowledgement, silences, notes, agents woken, sessions on its machines); the runbook and the dashboard. Text from outside Beacon is cleaned of control and invisible characters, cut, and listed underuntrusted. - Notes:
POST /api/v1/alerts/{id}/notesandadd_note(alerts:write) leave a note on an alert; the card shows the latest three, and each is audited and echoed to the chat. - Timeline:
GET /api/v1/alerts/{id}/timelineandget_timeline: started, notified, buzzed, Pushover, acknowledged, notes, silences, agents woken, changes, sessions and resolved, in time order. - Change events: the gateway takes
POST /api/v1/changes(Beacon's own form) andPOST /api/v1/changes/flux(Flux'sgenericprovider) with the new scopechanges:write; they are kept forchanges.keep(30 days by default) and listed byGET /api/v1/changesandlist_changes.
- Configured through Beacon (
docs/catalog.md): the catalogue (probe locations, heartbeats, resources), the probe targets (in named sets that keep the file names'all-,overseas-,mainland-and<location>-prefixes) and the module file live in the database. Changes are checked as the files were and take effect at once, withoutSIGHUP; probes get the same answers byte for byte.- Every change is a version with who made it, when, through what (
api,mcp,cli), a note, and every item's value before and after; it is audited and echoed to the alert chat. A change can be reverted unless a later one touched the same items. - REST under
/api/v1/config(locations,heartbeats,resources,targets,modules, each item in the shape of its file;history,history/{version},history/{version}/revert) and MCP toolsget_config,put_config,delete_config,list_config_changes,get_config_change,revert_config_change. New scopeconfig:write; reads takestatus:read. New error codesconfig.invalid,config.not_found,config.conflict. - CLI:
config import DIR [-dry-run],config export DIR(the layoutcatalog/*.yaml,targets/*.yaml,targets/modules.yml; the round trip keeps the content, not the comments of the catalogue and target files),config history,config revert VERSION. - The first start imports the files
catalog_dir,gateway.targets_dirandgateway.modules_filename into a database that holds no configuration yet. After that,SIGHUPimports them only when nothing was changed through Beacon since the last import, and says why not otherwise.check-configvalidates the files and the configuration in the database.
- Every change is a version with who made it, when, through what (
rc.1 (2026-11-01)
- Goals: Beacon is infrastructure for AI agents that run operations: it sees (monitoring), reaches (an SSH channel) and connects (one platform for people and agents). See
docs/goals.md. - The SSH channel (
docs/ssh.md), on port 17002 whenssh.ca_key_fileis set: agents reach machines with their ownssh,scp,sftp,rsyncandssh -L, the user name naming the machine, and never hold a key. Beacon signs a certificate valid for five minutes for each connection; machines trust only its certificate authority.- Every session is recorded (asciicast v3, kept 180 days by default); an interactive bash is broken into its commands with their exit statuses; the alert chat hears what agents did, batched per agent and machine.
- MCP tools and REST routes:
list_machines(with anssh_configfor the agent's own ssh),run_command,read_file,write_file,edit_file,list_sessions,get_session,add_machine,remove_machine,pause_ssh,resume_ssh. - CLI:
machine add|list|remove|ca,ssh pause|resume|status,token create … -ssh-key KEY -machines a,b,token ssh-key,token machines. - New scopes
machines:ssh,machines:write,sessions:read. Beacon does not review commands; the pause switch and each token's machines are the brakes.
0.2.0
rc.4 (2026-10-31)
- Probe retries per location:
probe: {retries: 1}tries a probe again at once when it fails without an answer (DNS, connect, timeout), for a machine whose connections drop now and then. Every result now comes withlinkos_probe_attempts.
rc.3 (2026-10-31)
- Standby CDN nodes: a location may be
standby: truein its rotation; the rotation check labels nodesrole="primary"or"standby". - Probe settings per location:
probe: {timeout: …}lengthens the probes' timeout on one machine. The gateway serves an agent's settings onGET /api/v1/agent; agents ask for them and keep working with a gateway that does not have the route. Agents probe up to 16 targets at once (was 8). docs/catalog.md: the catalogue, targets and module file.
rc.2 (2026-10-31)
The project is renamed Beacon · 烽火 (was LinkOS Status, openlinkos/status), and grows from an alert bridge into a monitoring service.
- Renamed: module
github.com/openlinkos/beacon, binarieslinkos-beaconandlinkos-probe, imageghcr.io/openlinkos/beacon, paths/etc/linkos-beaconand/var/lib/linkos-beacon, metric prefixlinkos_beacon_, token prefixlbt_. The image's health command islinkos-beacon healthcheck. - Gateway for machines (port 17006): per-machine tokens from
linkos-beacon enroll probe|host|heartbeat NAME, labels set from the catalogue, expired machines refused, targets and modules handed to probes, alerts from the rule engine and fromalerts:sendtokens, metric queries formetrics:read. - Router in place of Alertmanager: grouping, inhibition, silences and the Watchdog inside the service. Rule engines post to
/api/v2/alertsas they would to Alertmanager. Thealertmanagerconfiguration section and/hooks/alertmanagerare gone;rules.token_fileandroutingreplace them. linkos-probe agent: one process per probe machine that fetches its targets and modules, probes them with failure reasons, reads host metrics and heartbeats, and pushes everything with a disk queue. About 15 MB resident.- CDN rotation check: CDN nodes against their clusters' DNS answers.
- The catalogue links a location to its machine by name: an expired
vpsof the same name ends the location. - rc.1 was never published: its release pointed at the old repository name.
0.1.0
rc.1 (2026-10-30)
First pre-release, as LinkOS Status: the alert bridge between Alertmanager and the people on call (Feishu cards with acknowledge and silence, escalation to the Feishu app and Pushover, the group bot as fallback, budget control, the healthchecks.io ping), the REST API and the MCP server, the catalogue's metrics, and drills.