Every agent can have its own computer. A session that needs one wakes it: a home of its own on g1t cloud, one per agent and never shared, where it runs commands, reads and writes files and keeps what it made, with each session working in its own folder under a shared home; after ten idle minutes it sleeps, its home kept as a snapshot and restored when it wakes, and Reset wipes the home while memory and artifacts stay. Its shell and files are abilities with the usual choices, Alone, Alone when asked, Ask first or Never, offered only inside sessions and never to a chat reply; every command shows on the session with its output, and the agent's new Computer tab shows the state, the disk used of the five gigabytes included, the recent commands, and Wake, Put to sleep and Reset. Machine time counts only while it is awake, on the sandbox lines of the ledger that name the agent and who asked, held to the same spend caps as the session; the disk itself costs nothing in this version. The runner gained a long-lived supervisor that answers the computer's requests inside the container, and the runner service a computer per agent that keeps its snapshot in the agent homes bucket when one is attached, and says so when none is. The REST API and the agent tool can read a computer, wake it, put it to sleep and reset it. The agents, abilities, sessions, runners, billing and deploy guides say how it works and what an operator sets up; pinning a computer to your own runner, its browser and take-over come next.
| 510 | 510 | ], | |
| 511 | 511 | ), | |
| 512 | 512 | ( | |
| 513 | + | "Agents' computers", | |
| 514 | + | "Each workspace agent has a computer of its own on g1t cloud: a persistent home its sessions run commands on, which sleeps when idle and is saved as it was. Its state and recent commands, and waking, sleeping and resetting it.", | |
| 515 | + | &[ | |
| 516 | + | Op::GetAgentComputer, | |
| 517 | + | Op::WakeAgentComputer, | |
| 518 | + | Op::SleepAgentComputer, | |
| 519 | + | Op::ResetAgentComputer, | |
| 520 | + | Op::ListAgentComputerCommands, | |
| 521 | + | ], | |
| 522 | + | ), | |
| 523 | + | ( | |
| 513 | 524 | "Webhooks", | |
| 514 | 525 | "Signed HTTPS requests sent to your own address as things happen, for a repository or a whole workspace.", | |
| 515 | 526 | &[ | |
| ⋯ | |||
| 697 | 708 | Op::DeleteActionsVariable => "Delete a variable", | |
| 698 | 709 | Op::ListRunners => "List self-hosted runners", | |
| 699 | 710 | Op::ListRunnerGroups => "List runner groups", | |
| 711 | + | Op::GetAgentComputer => "Get an agent's computer", | |
| 712 | + | Op::WakeAgentComputer => "Wake an agent's computer", | |
| 713 | + | Op::SleepAgentComputer => "Put an agent's computer to sleep", | |
| 714 | + | Op::ResetAgentComputer => "Reset an agent's computer", | |
| 715 | + | Op::ListAgentComputerCommands => "List an agent's computer's commands", | |
| 700 | 716 | Op::GetRunnerSettings => "Get runner settings", | |
| 701 | 717 | Op::CreateRunnerRegistrationToken => "Create a runner registration token", | |
| 702 | 718 | Op::RemoveRunner => "Remove a self-hosted runner", | |
| ⋯ | |||
| 787 | 803 | fn may_need_payment(op: Op) -> Option<&'static str> { | |
| 788 | 804 | match op { | |
| 789 | 805 | Op::AssignIssue | Op::PlanWork | Op::ApplyPlan => Some("The workspace has no agent credit."), | |
| 806 | + | Op::WakeAgentComputer => Some("The workspace's plan refuses compute: it is paused, or over its limit."), | |
| 790 | 807 | Op::UpdateRepo | Op::SetRepoVisibility | Op::TransferRepo => Some( | |
| 791 | 808 | "A free workspace's private storage has no room for this private repository.", | |
| 792 | 809 | ), | |
| 72 | 72 | /// The artifacts service (services/artifacts): docs, slides, designs and | |
| 73 | 73 | /// dashboards (folios), for the artifact routes and tool. | |
| 74 | 74 | pub artifacts: Fetcher, | |
| 75 | + | /// The agents service (services/agents): workspace agents' own computers. | |
| 76 | + | pub agents: Fetcher, | |
| 75 | 77 | /// Where the request came in, for its audit entries. | |
| 76 | 78 | pub audit: crate::audit::AuditContext, | |
| 77 | 79 | /// Set for a request made with an agent's token: all it may do. | |
| ⋯ | |||
| 99 | 101 | deployments: env.service("DEPLOYMENTS")?, | |
| 100 | 102 | packages: env.service("PACKAGES")?, | |
| 101 | 103 | artifacts: env.service("ARTIFACTS")?, | |
| 104 | + | agents: env.service("AGENTS")?, | |
| 102 | 105 | scope: None, | |
| 103 | 106 | audit: crate::audit::AuditContext::default(), | |
| 104 | 107 | addresses: crate::addresses::Addresses::from_env(env), | |
| ⋯ | |||
| 239 | 242 | UpdateRunnerGroup, | |
| 240 | 243 | DeleteRunnerGroup, | |
| 241 | 244 | UpdateRunnerSettings, | |
| 245 | + | // A workspace agent's own computer (services/agents computer.ts). | |
| 246 | + | GetAgentComputer, | |
| 247 | + | WakeAgentComputer, | |
| 248 | + | SleepAgentComputer, | |
| 249 | + | ResetAgentComputer, | |
| 250 | + | ListAgentComputerCommands, | |
| 242 | 251 | ListCollaborators, | |
| 243 | 252 | AddCollaborator, | |
| 244 | 253 | UpdateCollaborator, | |
| ⋯ | |||
| 698 | 707 | } | |
| 699 | 708 | ||
| 700 | 709 | impl Op { | |
| 701 | − | pub const ALL: [Op; 345] = [ | |
| 710 | + | pub const ALL: [Op; 350] = [ | |
| 702 | 711 | Op::Whoami, | |
| 703 | 712 | Op::GetWorkspace, | |
| 704 | 713 | Op::CreateWorkspace, | |
| ⋯ | |||
| 830 | 839 | Op::UpdateRunnerGroup, | |
| 831 | 840 | Op::DeleteRunnerGroup, | |
| 832 | 841 | Op::UpdateRunnerSettings, | |
| 842 | + | Op::GetAgentComputer, | |
| 843 | + | Op::WakeAgentComputer, | |
| 844 | + | Op::SleepAgentComputer, | |
| 845 | + | Op::ResetAgentComputer, | |
| 846 | + | Op::ListAgentComputerCommands, | |
| 833 | 847 | Op::ListCollaborators, | |
| 834 | 848 | Op::AddCollaborator, | |
| 835 | 849 | Op::UpdateCollaborator, | |
| ⋯ | |||
| 1184 | 1198 | Op::UpdateRunnerGroup => "update_runner_group", | |
| 1185 | 1199 | Op::DeleteRunnerGroup => "delete_runner_group", | |
| 1186 | 1200 | Op::UpdateRunnerSettings => "update_runner_settings", | |
| 1201 | + | Op::GetAgentComputer => "get_agent_computer", | |
| 1202 | + | Op::WakeAgentComputer => "wake_agent_computer", | |
| 1203 | + | Op::SleepAgentComputer => "sleep_agent_computer", | |
| 1204 | + | Op::ResetAgentComputer => "reset_agent_computer", | |
| 1205 | + | Op::ListAgentComputerCommands => "list_agent_computer_commands", | |
| 1187 | 1206 | Op::ListCollaborators => "list_collaborators", | |
| 1188 | 1207 | Op::AddCollaborator => "add_collaborator", | |
| 1189 | 1208 | Op::UpdateCollaborator => "update_collaborator", | |
| ⋯ | |||
| 1616 | 1635 | Op::UpdateRunnerSettings => { | |
| 1617 | 1636 | "Change where g1t agent work runs and whether pull requests from forks may use self-hosted runners, for a workspace or one repository. Left out is unchanged; `inherit` drops a repository's own settings. Allowing forks lets anyone who can open a pull request run code on your machines. Owners of the workspace, or admins of the repository." | |
| 1618 | 1637 | } | |
| 1638 | + | Op::GetAgentComputer => { | |
| 1639 | + | "A workspace agent's own computer: its `status` (`state` asleep, waking, awake or sleeping, and `since`; `disk_used_bytes` of `disk_cap_bytes`, 5 GB; `last_woke_at`, `last_slept_at`; the saved home's `snapshot_bytes` and `snapshot_at`; `where`, g1t_cloud; `disk_attached`, false while the installation has no storage for homes; a `problem` the owner should know of; `delete_after` once the agent was archived), its recent `commands` newest first, and `can_manage`, whether you may wake, sleep or reset it. Members of the workspace; a personal agent's only its member and the owners." | |
| 1640 | + | } | |
| 1641 | + | Op::WakeAgentComputer => { | |
| 1642 | + | "Wake an agent's computer: the container starts, its saved home is restored, and its time is metered as sandbox time under the agent until it sleeps. Sessions wake it by themselves; this is for a person. Refused with `payment_required` when the workspace's plan refuses compute. Owners, or the member whose personal agent it is. Returns what get_agent_computer returns." | |
| 1643 | + | } | |
| 1644 | + | Op::SleepAgentComputer => { | |
| 1645 | + | "Put an agent's computer to sleep: its home is saved and the container stops, with its time on the ledger. Refused with `conflict` while a command is running, or when the home is over its 5 GB cap and can't be saved (the message names the largest directories). Owners, or the member whose personal agent it is. Returns what get_agent_computer returns." | |
| 1646 | + | } | |
| 1647 | + | Op::ResetAgentComputer => { | |
| 1648 | + | "Reset an agent's computer: it is stopped if awake, its saved home is deleted, and its command history is cleared. The agent's memory and artifacts are untouched. Owners, or the member whose personal agent it is. Returns what get_agent_computer returns." | |
| 1649 | + | } | |
| 1650 | + | Op::ListAgentComputerCommands => { | |
| 1651 | + | "The commands an agent's computer ran most recently, newest first, up to 50: each with its `cmd`, `cwd`, `exit_code`, `duration_ms`, `output` (cut at 64 KB, `truncated` when so), `timed_out`, the `session_id` it ran in and who `asked_by`. Members of the workspace; a personal agent's only its member and the owners." | |
| 1652 | + | } | |
| 1619 | 1653 | Op::ImportIssue => { | |
| 1620 | 1654 | "Open an issue from a ticket in Jira or Linear, or from a Sentry issue, by its key or address. The issue is linked to it: agents read the original, and when the work lands the ticket is told. Importing the same ticket again returns the issue already made. With assign, a g1t agent starts on it." | |
| 1621 | 1655 | } | |
| ⋯ | |||
| 2759 | 2793 | &["setting"], | |
| 2760 | 2794 | ), | |
| 2761 | 2795 | Op::ListRunners | Op::GetRunnerSettings => object(runners_owner(json!({})), &[]), | |
| 2796 | + | Op::GetAgentComputer | Op::WakeAgentComputer | Op::SleepAgentComputer | Op::ResetAgentComputer | Op::ListAgentComputerCommands => object( | |
| 2797 | + | json!({ | |
| 2798 | + | "workspace": workspace_schema(), | |
| 2799 | + | "agent": { "type": "string", "description": "The agent's handle, without the @." }, | |
| 2800 | + | }), | |
| 2801 | + | &["workspace", "agent"], | |
| 2802 | + | ), | |
| 2762 | 2803 | Op::CreateRunnerRegistrationToken => object( | |
| 2763 | 2804 | runners_owner(json!({ | |
| 2764 | 2805 | "group": { "type": "string", "description": "A workspace's runner group, by name or id, for the runners it registers. The default group if left out." }, | |
| ⋯ | |||
| 3452 | 3493 | | Op::UpdateRunnerGroup | |
| 3453 | 3494 | | Op::DeleteRunnerGroup | |
| 3454 | 3495 | | Op::UpdateRunnerSettings | |
| 3496 | + | | Op::GetAgentComputer | |
| 3497 | + | | Op::WakeAgentComputer | |
| 3498 | + | | Op::SleepAgentComputer | |
| 3499 | + | | Op::ResetAgentComputer | |
| 3500 | + | | Op::ListAgentComputerCommands | |
| 3455 | 3501 | | Op::ListMyRepoInvitations | |
| 3456 | 3502 | | Op::AcceptRepoInvitation | |
| 3457 | 3503 | | Op::DeclineRepoInvitation | |
| ⋯ | |||
| 3653 | 3699 | integrations, | |
| 3654 | 3700 | webhooks, | |
| 3655 | 3701 | actions, | |
| 3702 | + | agents, | |
| 3656 | 3703 | .. | |
| 3657 | 3704 | } = services; | |
| 3658 | 3705 | let workspace = || text(input, "workspace").to_lowercase(); | |
| ⋯ | |||
| 5063 | 5110 | Op::ListRunnerGroups => { | |
| 5064 | 5111 | pass(actions, "runner_groups", &json!({ "actor": actor(), "workspace": workspace() })).await | |
| 5065 | 5112 | } | |
| 5113 | + | // A workspace agent's own computer: the agents service checks who may | |
| 5114 | + | // see it and who may act on it (services/agents computer.ts). | |
| 5115 | + | Op::GetAgentComputer | |
| 5116 | + | | Op::WakeAgentComputer | |
| 5117 | + | | Op::SleepAgentComputer | |
| 5118 | + | | Op::ResetAgentComputer | |
| 5119 | + | | Op::ListAgentComputerCommands => { | |
| 5120 | + | let handle = text(input, "agent").trim().trim_start_matches('@').to_lowercase(); | |
| 5121 | + | if workspace().is_empty() || handle.is_empty() { | |
| 5122 | + | return failed(FailureCode::Invalid, "Name the workspace and the agent's handle."); | |
| 5123 | + | } | |
| 5124 | + | let method = match self { | |
| 5125 | + | Op::GetAgentComputer => "computer", | |
| 5126 | + | Op::WakeAgentComputer => "computer_wake", | |
| 5127 | + | Op::SleepAgentComputer => "computer_sleep", | |
| 5128 | + | Op::ResetAgentComputer => "computer_reset", | |
| 5129 | + | _ => "computer_commands", | |
| 5130 | + | }; | |
| 5131 | + | pass(agents, method, &json!({ "workspace": workspace(), "handle": handle, "viewer": actor() })).await | |
| 5132 | + | } | |
| 5066 | 5133 | Op::CreateRunnerGroup | Op::UpdateRunnerGroup => { | |
| 5067 | 5134 | let mut args = json!({ "actor": actor(), "workspace": workspace() }); | |
| 5068 | 5135 | if self == Op::UpdateRunnerGroup { | |
| 3671 | 3671 | } | |
| 3672 | 3672 | ] | |
| 3673 | 3673 | }, | |
| 3674 | + | "get_agent_computer": { | |
| 3675 | + | "notes": "The computer is asleep until a session or a person wakes it; while awake its time is sandbox time on the workspace's usage, under the agent and whoever asked. `disk_cap_bytes` is 5 GB, included, with no disk charge; `disk_attached` is false while the installation has no storage for homes, in which case the home is forgotten at every sleep.", | |
| 3676 | + | "params": { | |
| 3677 | + | "workspace": "flagon-io", | |
| 3678 | + | "agent": "margo" | |
| 3679 | + | }, | |
| 3680 | + | "response": { | |
| 3681 | + | "status": { | |
| 3682 | + | "agent_id": "agt_01k7a0b1c2d3e4f5g6h7j8k9mn", | |
| 3683 | + | "state": "asleep", | |
| 3684 | + | "since": "2026-10-10T09:42:10.000Z", | |
| 3685 | + | "disk_used_bytes": 734003200, | |
| 3686 | + | "disk_cap_bytes": 5000000000, | |
| 3687 | + | "last_woke_at": "2026-10-10T09:12:03.000Z", | |
| 3688 | + | "last_slept_at": "2026-10-10T09:42:10.000Z", | |
| 3689 | + | "snapshot_bytes": 212337664, | |
| 3690 | + | "snapshot_at": "2026-10-10T09:42:08.000Z", | |
| 3691 | + | "where": "g1t_cloud", | |
| 3692 | + | "disk_attached": true, | |
| 3693 | + | "problem": null, | |
| 3694 | + | "delete_after": null | |
| 3695 | + | }, | |
| 3696 | + | "commands": [ | |
| 3697 | + | { | |
| 3698 | + | "id": "cmd_4f1c9e2a7b3d5f6081a2", | |
| 3699 | + | "session_id": "asn_01k7b2c3d4e5f6g7h8j9k0mnpq", | |
| 3700 | + | "asked_by": "ana", | |
| 3701 | + | "started_at": "2026-10-10T09:31:44.000Z", | |
| 3702 | + | "cmd": "npm test", | |
| 3703 | + | "cwd": "/home/agent/sessions/asn_01k7b2c3d4e5f6g7h8j9k0mnpq/web", | |
| 3704 | + | "exit_code": 0, | |
| 3705 | + | "duration_ms": 41230, | |
| 3706 | + | "output": "> web@1.0.0 test\n> node --test\n\nℹ tests 128\nℹ pass 128\nℹ fail 0", | |
| 3707 | + | "truncated": false, | |
| 3708 | + | "timed_out": false | |
| 3709 | + | } | |
| 3710 | + | ], | |
| 3711 | + | "can_manage": true | |
| 3712 | + | } | |
| 3713 | + | }, | |
| 3714 | + | "wake_agent_computer": { | |
| 3715 | + | "params": { | |
| 3716 | + | "workspace": "flagon-io", | |
| 3717 | + | "agent": "margo" | |
| 3718 | + | }, | |
| 3719 | + | "response": { | |
| 3720 | + | "status": { | |
| 3721 | + | "agent_id": "agt_01k7a0b1c2d3e4f5g6h7j8k9mn", | |
| 3722 | + | "state": "awake", | |
| 3723 | + | "since": "2026-10-10T10:02:17.000Z", | |
| 3724 | + | "disk_used_bytes": 734003200, | |
| 3725 | + | "disk_cap_bytes": 5000000000, | |
| 3726 | + | "last_woke_at": "2026-10-10T10:02:17.000Z", | |
| 3727 | + | "last_slept_at": "2026-10-10T09:42:10.000Z", | |
| 3728 | + | "snapshot_bytes": 212337664, | |
| 3729 | + | "snapshot_at": "2026-10-10T09:42:08.000Z", | |
| 3730 | + | "where": "g1t_cloud", | |
| 3731 | + | "disk_attached": true, | |
| 3732 | + | "problem": null, | |
| 3733 | + | "delete_after": null | |
| 3734 | + | }, | |
| 3735 | + | "commands": [], | |
| 3736 | + | "can_manage": true | |
| 3737 | + | } | |
| 3738 | + | }, | |
| 3739 | + | "sleep_agent_computer": { | |
| 3740 | + | "params": { | |
| 3741 | + | "workspace": "flagon-io", | |
| 3742 | + | "agent": "margo" | |
| 3743 | + | }, | |
| 3744 | + | "response": { | |
| 3745 | + | "status": { | |
| 3746 | + | "agent_id": "agt_01k7a0b1c2d3e4f5g6h7j8k9mn", | |
| 3747 | + | "state": "asleep", | |
| 3748 | + | "since": "2026-10-10T10:20:51.000Z", | |
| 3749 | + | "disk_used_bytes": 751239168, | |
| 3750 | + | "disk_cap_bytes": 5000000000, | |
| 3751 | + | "last_woke_at": "2026-10-10T10:02:17.000Z", | |
| 3752 | + | "last_slept_at": "2026-10-10T10:20:51.000Z", | |
| 3753 | + | "snapshot_bytes": 219152384, | |
| 3754 | + | "snapshot_at": "2026-10-10T10:20:49.000Z", | |
| 3755 | + | "where": "g1t_cloud", | |
| 3756 | + | "disk_attached": true, | |
| 3757 | + | "problem": null, | |
| 3758 | + | "delete_after": null | |
| 3759 | + | }, | |
| 3760 | + | "commands": [], | |
| 3761 | + | "can_manage": true | |
| 3762 | + | } | |
| 3763 | + | }, | |
| 3764 | + | "reset_agent_computer": { | |
| 3765 | + | "params": { | |
| 3766 | + | "workspace": "flagon-io", | |
| 3767 | + | "agent": "margo" | |
| 3768 | + | }, | |
| 3769 | + | "response": { | |
| 3770 | + | "status": { | |
| 3771 | + | "agent_id": "agt_01k7a0b1c2d3e4f5g6h7j8k9mn", | |
| 3772 | + | "state": "asleep", | |
| 3773 | + | "since": "2026-10-10T10:25:00.000Z", | |
| 3774 | + | "disk_used_bytes": 0, | |
| 3775 | + | "disk_cap_bytes": 5000000000, | |
| 3776 | + | "last_woke_at": "2026-10-10T10:02:17.000Z", | |
| 3777 | + | "last_slept_at": "2026-10-10T10:20:51.000Z", | |
| 3778 | + | "snapshot_bytes": null, | |
| 3779 | + | "snapshot_at": null, | |
| 3780 | + | "where": "g1t_cloud", | |
| 3781 | + | "disk_attached": true, | |
| 3782 | + | "problem": null, | |
| 3783 | + | "delete_after": null | |
| 3784 | + | }, | |
| 3785 | + | "commands": [], | |
| 3786 | + | "can_manage": true | |
| 3787 | + | } | |
| 3788 | + | }, | |
| 3789 | + | "list_agent_computer_commands": { | |
| 3790 | + | "params": { | |
| 3791 | + | "workspace": "flagon-io", | |
| 3792 | + | "agent": "margo" | |
| 3793 | + | }, | |
| 3794 | + | "response": [ | |
| 3795 | + | { | |
| 3796 | + | "id": "cmd_4f1c9e2a7b3d5f6081a2", | |
| 3797 | + | "session_id": "asn_01k7b2c3d4e5f6g7h8j9k0mnpq", | |
| 3798 | + | "asked_by": "ana", | |
| 3799 | + | "started_at": "2026-10-10T09:31:44.000Z", | |
| 3800 | + | "cmd": "npm test", | |
| 3801 | + | "cwd": "/home/agent/sessions/asn_01k7b2c3d4e5f6g7h8j9k0mnpq/web", | |
| 3802 | + | "exit_code": 0, | |
| 3803 | + | "duration_ms": 41230, | |
| 3804 | + | "output": "> web@1.0.0 test\n> node --test\n\nℹ tests 128\nℹ pass 128\nℹ fail 0", | |
| 3805 | + | "truncated": false, | |
| 3806 | + | "timed_out": false | |
| 3807 | + | }, | |
| 3808 | + | { | |
| 3809 | + | "id": "cmd_0a9b8c7d6e5f4a3b2c1d", | |
| 3810 | + | "session_id": "asn_01k7b2c3d4e5f6g7h8j9k0mnpq", | |
| 3811 | + | "asked_by": "ana", | |
| 3812 | + | "started_at": "2026-10-10T09:30:02.000Z", | |
| 3813 | + | "cmd": "git clone https://g1t.sh/flagon-io/web.git && cd web && npm ci", | |
| 3814 | + | "cwd": "/home/agent/sessions/asn_01k7b2c3d4e5f6g7h8j9k0mnpq", | |
| 3815 | + | "exit_code": 0, | |
| 3816 | + | "duration_ms": 58904, | |
| 3817 | + | "output": "Cloning into 'web'...\nadded 412 packages in 48s", | |
| 3818 | + | "truncated": false, | |
| 3819 | + | "timed_out": false | |
| 3820 | + | } | |
| 3821 | + | ] | |
| 3822 | + | }, | |
| 3674 | 3823 | "create_runner_group": { | |
| 3675 | 3824 | "params": { | |
| 3676 | 3825 | "workspace": "flagon-io" |
| 129 | 129 | Op::Packages(_) => return as_is, | |
| 130 | 130 | // Artifacts are shaped by the API itself, in `snake_case`. | |
| 131 | 131 | Op::Folios(_) => return as_is, | |
| 132 | + | // Agents' computers travel in `snake_case` from the agents service. | |
| 133 | + | Op::GetAgentComputer | Op::WakeAgentComputer | Op::SleepAgentComputer | Op::ResetAgentComputer | Op::ListAgentComputerCommands => return as_is, | |
| 132 | 134 | // Built by the API itself, in `snake_case`. | |
| 133 | 135 | Op::ListSecurityAlerts => return through::<Vec<crate::alerts::SecurityAlert>>(op, as_is), | |
| 134 | 136 | Op::DismissSecurityAlert | Op::ReopenSecurityAlert => { |
| 866 | 866 | route("POST", "/workspaces/:workspace/actions/runner-groups", Op::CreateRunnerGroup, &[]), | |
| 867 | 867 | route("PATCH", "/workspaces/:workspace/actions/runner-groups/:id", Op::UpdateRunnerGroup, &[]), | |
| 868 | 868 | route("DELETE", "/workspaces/:workspace/actions/runner-groups/:id", Op::DeleteRunnerGroup, &[]), | |
| 869 | + | // A workspace agent's own computer. | |
| 870 | + | route("GET", "/workspaces/:workspace/agents/:agent/computer", Op::GetAgentComputer, &[]), | |
| 871 | + | route("POST", "/workspaces/:workspace/agents/:agent/computer/wake", Op::WakeAgentComputer, &[]), | |
| 872 | + | route("POST", "/workspaces/:workspace/agents/:agent/computer/sleep", Op::SleepAgentComputer, &[]), | |
| 873 | + | route("POST", "/workspaces/:workspace/agents/:agent/computer/reset", Op::ResetAgentComputer, &[]), | |
| 874 | + | route("GET", "/workspaces/:workspace/agents/:agent/computer/commands", Op::ListAgentComputerCommands, &[]), | |
| 869 | 875 | route("POST", "/repos/:owner/:name/plans", Op::PlanWork, &[]), | |
| 870 | 876 | route("GET", "/repos/:owner/:name/plans/:plan", Op::GetPlan, &[]), | |
| 871 | 877 | route( |
| 195 | 195 | a("message", Op::MessageAgent, "Tell the agent on a pull request something, or ask another agent"), | |
| 196 | 196 | a("answer", Op::AnswerMessage, "Answer a question or handoff sent to you"), | |
| 197 | 197 | a("take_messages", Op::TakeMessages, "For a g1t agent: messages not seen yet"), | |
| 198 | + | a("computer", Op::GetAgentComputer, "A workspace agent's own computer: state, disk, recent commands"), | |
| 199 | + | a("wake_computer", Op::WakeAgentComputer, "Wake a workspace agent's computer (metered until it sleeps)"), | |
| 200 | + | a("sleep_computer", Op::SleepAgentComputer, "Save its home and put it to sleep"), | |
| 201 | + | a("reset_computer", Op::ResetAgentComputer, "Wipe its home; memory and artifacts are kept"), | |
| 202 | + | a("computer_commands", Op::ListAgentComputerCommands, "The commands it ran most recently, with output"), | |
| 198 | 203 | ], | |
| 199 | 204 | }, | |
| 200 | 205 | Tool { |
| 35 | 35 | // Packages: list_packages, their settings, deleting and restoring them. | |
| 36 | 36 | { "binding": "PACKAGES", "service": "g1t-packages" }, | |
| 37 | 37 | // Artifacts (folios): the artifact tool and /workspaces/{ws}/artifacts. | |
| 38 | − | { "binding": "ARTIFACTS", "service": "g1t-artifacts" } | |
| 38 | + | { "binding": "ARTIFACTS", "service": "g1t-artifacts" }, | |
| 39 | + | // Workspace agents' own computers: /workspaces/{ws}/agents/{agent}/computer. | |
| 40 | + | { "binding": "AGENTS", "service": "g1t-agents" } | |
| 39 | 41 | ], | |
| 40 | 42 | // GitHub Actions artifacts older runners kept, in chunks, with KV's own | |
| 41 | 43 | // expiry, read until it passes (and cache |
| 62 | 62 | ||
| 63 | 63 | ### Its computer | |
| 64 | 64 | ||
| 65 | − | A shell, files, a browser and web search, on a computer of the agent's | |
| 66 | − | own. These are listed so you can see what is coming, and are marked | |
| 67 | − | **Coming** until the agent computer exists. Nothing can be set for them | |
| 68 | − | yet. | |
| 65 | + | What the agent may do on [its own computer](/guides/agents/#its-computer), | |
| 66 | + | in its sessions. Chat replies never use the computer, whatever is set here. | |
| 69 | 67 | ||
| 68 | + | | Ability | Tools it offers | Kind | Default | | |
| 69 | + | | --- | --- | --- | --- | | |
| 70 | + | | Shell | `run_command` | Write | Alone when asked for it | | |
| 71 | + | | Files | `computer_read_file` · `computer_write_file` | Write | Alone | | |
| 72 | + | | Browser | — | Send | Coming | | |
| 73 | + | | Web search | — | Read | Coming | | |
| 74 | + | ||
| 75 | + | Set to **Never**, an ability's tools are not offered to the agent at all, | |
| 76 | + | and a call for one anyway is refused with the rule. For the shell at | |
| 77 | + | **Alone when asked for it**, the session's goal or a message steering it | |
| 78 | + | counts as asking when it names running, building, testing, installing, | |
| 79 | + | cloning or the like; otherwise the command waits on an Ask-first card, with | |
| 80 | + | the command on it. Files are alone by default, since nothing leaves the | |
| 81 | + | computer. A browser and web search are marked **Coming** until they exist; | |
| 82 | + | nothing can be set for them yet. | |
| 83 | + | ||
| 70 | 84 | ### Integrations | |
| 71 | 85 | ||
| 72 | 86 | Every integration the workspace has connected lists what an agent can do | |
| ⋯ | |||
| 183 | 197 | agents service's `add_mcp_server`, `refresh_mcp_server` and | |
| 184 | 198 | `remove_mcp_server`; they never travel with a change. | |
| 185 | 199 | ||
| 200 | + | The computer itself has routes of its own under the agent: | |
| 201 | + | `GET /workspaces/{workspace}/agents/{agent}/computer` for its state and | |
| 202 | + | recent commands, `POST …/computer/wake`, `…/computer/sleep` and | |
| 203 | + | `…/computer/reset`, and `GET …/computer/commands`; in MCP, the `agent` | |
| 204 | + | tool's `computer`, `wake_computer`, `sleep_computer`, `reset_computer` and | |
| 205 | + | `computer_commands` actions, all under `agents:run`. | |
| 206 | + | ||
| 186 | 207 | ## Next | |
| 187 | 208 | ||
| 188 | 209 | - [Agents](/guides/agents/): hiring, changing and running agents. | |
| 70 | 70 | - **Everything in a tree is paid by the agent at its root, within the root's | |
| 71 | 71 | cap.** A chain of sessions can never escape the budget that started it. | |
| 72 | 72 | ||
| 73 | + | ## Commands on its computer | |
| 74 | + | ||
| 75 | + | A session is where an agent uses [its own computer](/guides/agents/#its-computer). | |
| 76 | + | When its shell or files ability is on, the session has `run_command`, | |
| 77 | + | `computer_read_file` and `computer_write_file`; the first command wakes the | |
| 78 | + | computer, which takes a few seconds, and it sleeps ten minutes after the | |
| 79 | + | last one. Each session works in its own directory, `/home/agent/sessions/<id>`, | |
| 80 | + | in the agent's home, so what one session cloned or installed is there for | |
| 81 | + | the next. | |
| 82 | + | ||
| 83 | + | Every command is an entry in the session's transcript: the command, the | |
| 84 | + | directory it ran in, its exit code and how long it took, with its output | |
| 85 | + | folded under it (cut at 8,000 characters there; the computer's own page | |
| 86 | + | keeps up to 64 KB). The **Computer** section under the transcript lists the | |
| 87 | + | session's commands together, and links to the agent's Computer tab, which | |
| 88 | + | lists every session's. | |
| 89 | + | ||
| 90 | + | A command the abilities say to ask first waits on a card, like any other | |
| 91 | + | [Ask-first](/guides/agent-abilities/#the-levels) call: the session pauses | |
| 92 | + | at the end of its step until someone allows or denies it, and the command | |
| 93 | + | runs when it is allowed. A computer that cannot wake, because the | |
| 94 | + | workspace is paused or past its spend limit, is said in the agent's report | |
| 95 | + | rather than worked around. | |
| 96 | + | ||
| 73 | 97 | ## Statuses | |
| 74 | 98 | ||
| 75 | 99 | | Status | Means | |
| 780 | 780 | An agent also never does more for someone than that person could do | |
| 781 | 781 | themselves. See [what agents can do for whom](/guides/agent-access/). | |
| 782 | 782 | ||
| 783 | + | ## Its computer | |
| 784 | + | ||
| 785 | + | Every workspace agent has a computer of its own: a Linux machine on g1t | |
| 786 | + | cloud with git, Node, Python, Go, Rust, Java, .NET and Ruby, and a home, | |
| 787 | + | `/home/agent`, that stays between sessions. Clones, installed tools, build | |
| 788 | + | caches and notes are there the next time. It is the agent's alone; no two | |
| 789 | + | agents share one, and no person signs in to it. | |
| 790 | + | ||
| 791 | + | It is a persistent home, not an always-on machine: | |
| 792 | + | ||
| 793 | + | - **Sessions use it; chat replies never do.** A [session](/guides/agent-sessions/) | |
| 794 | + | runs commands with `run_command` and reads and writes files with | |
| 795 | + | `computer_read_file` and `computer_write_file`, as its | |
| 796 | + | [abilities](/guides/agent-abilities/#its-computer) allow. Each session | |
| 797 | + | works in its own directory, `/home/agent/sessions/<session id>`, in the | |
| 798 | + | shared home. A quick answer in chat never wakes a machine. | |
| 799 | + | - **It sleeps when idle.** Ten minutes after the last command with nothing | |
| 800 | + | running, its home is saved as it was and the machine stops. The next | |
| 801 | + | command wakes it and puts the home back, which takes a few seconds. A | |
| 802 | + | command that was running at the time is never cut off for idleness. | |
| 803 | + | - **Its home holds 5 GB.** That is included with the agent, with no charge | |
| 804 | + | for the disk. It is a hard cap: a home over it cannot be saved, the | |
| 805 | + | Computer tab says which directories are largest, and the agent is asked | |
| 806 | + | to trim them. After an hour over the cap, the machine stops without | |
| 807 | + | saving. | |
| 808 | + | - **It costs machine time while awake.** Awake time is | |
| 809 | + | [sandbox time](/guides/usage-and-billing/#sandbox-time), at cost plus | |
| 810 | + | 20%, under the agent and whoever asked for the session that woke it. | |
| 811 | + | Asleep it costs nothing. Waking it is admitted the way an agent run is: | |
| 812 | + | a paused workspace, or one past its limit, is refused and the agent | |
| 813 | + | says so in its report. | |
| 814 | + | - **Reset wipes the home.** The agent's memory and artifacts are kept; | |
| 815 | + | its files, clones and command history go. | |
| 816 | + | - **Archiving the agent** puts the computer to sleep and keeps its disk | |
| 817 | + | for 30 days, then deletes it. | |
| 818 | + | ||
| 819 | + | Every command runs as the agent in `bash`, with the output returned when it | |
| 820 | + | ends and a timeout of 120 seconds unless the agent asks for more (up to 30 | |
| 821 | + | minutes). The output is kept with the session and on the Computer tab, cut | |
| 822 | + | at 64 KB. Nothing waits for input, and nothing keeps running once the | |
| 823 | + | command ends. The agent cannot push to a repository from its computer; to | |
| 824 | + | change code it drafts an issue, as before. | |
| 825 | + | ||
| 826 | + | It runs on g1t cloud. Pinning an agent's computer to one of your own | |
| 827 | + | [runners](/guides/self-hosted-runners/), a browser of its own, web search | |
| 828 | + | and taking over its terminal are coming. | |
| 829 | + | ||
| 783 | 830 | ## The agent's page | |
| 784 | 831 | ||
| 785 | 832 | Each agent has a page at `g1t.sh/<workspace>/-/agents/<handle>`: | |
| ⋯ | |||
| 789 | 836 | | **Sessions** | Every session it is working on, then every one it worked on before, each child under the session that started it. See [sessions](/guides/agent-sessions/). | | |
| 790 | 837 | | **Skills** | The [skills](/guides/agent-skills/) it has: g1t's foundational ones and your library's, each on or off. | | |
| 791 | 838 | | **Abilities** | What it may do, in groups, with a level for each: alone, alone when asked for it, ask first, or never; whose connection an integration runs on; MCP servers owners add. See [agent abilities](/guides/agent-abilities/). | | |
| 839 | + | | **Computer** | [Its computer](#its-computer): asleep or awake and since when, its disk against the 5 GB it holds, where it runs, and the commands it ran most recently with their output. Owners (or the member, for a personal agent) wake it, put it to sleep, or reset it. | | |
| 792 | 840 | | **Memory** | What it remembers, by scope, with where each fact came from. Pin, correct or forget facts. See [agent memory](/guides/agent-memory/). | | |
| 793 | 841 | | **Routines** | Work it does on a schedule or when something happens. See [routines](/guides/agent-routines/). | | |
| 794 | 842 | | **Spend** | Its [effort](#effort) and what each level has cost it, suggestions to spend less, and spend this month against its budget: by day, kind of work, model and who asked, and its costliest sessions. | | |
| 192 | 192 | `resources.kv` in the manifest, and put the ids in the configs. | |
| 193 | 193 | 4. Queues: `npx wrangler queues create <queue>` for each queue in the | |
| 194 | 194 | manifest, including the dead-letter queue `g1t-events-dlq`. | |
| 195 | − | 5. R2: create `g1t-screenshots`, `g1t-actions-cache` and `g1t-git-packs`, | |
| 196 | − | with lifecycle rules: | |
| 195 | + | 5. R2: create `g1t-screenshots`, `g1t-actions-cache`, `g1t-git-packs` and | |
| 196 | + | `g1t-agent-homes`, with lifecycle rules: | |
| 197 | 197 | ||
| 198 | 198 | ```sh | |
| 199 | 199 | npx wrangler r2 bucket lifecycle add g1t-actions-cache expire-cache c/ --expire-days 30 --abort-multipart-days 1 | |
| 200 | 200 | npx wrangler r2 bucket lifecycle add g1t-actions-cache expire-artifacts a/ --expire-days 91 --abort-multipart-days 1 | |
| 201 | 201 | npx wrangler r2 bucket lifecycle add g1t-git-packs expire-packs packs/ --expire-days 7 --abort-multipart-days 1 | |
| 202 | + | npx wrangler r2 bucket lifecycle add g1t-agent-homes abort-uploads homes/ --abort-multipart-days 1 | |
| 202 | 203 | ``` | |
| 203 | 204 | ||
| 205 | + | `g1t-agent-homes` holds [agents' computers'](/guides/agents/#its-computer) | |
| 206 | + | saved homes, and is the one bucket a Worker does not bind until it | |
| 207 | + | exists: see [Agents' computers](#agents-computers) below. | |
| 208 | + | ||
| 204 | 209 | 6. The runner's base image: `node scripts/deploy.mjs build-base`, then | |
| 205 | 210 | commit `services/runner/base.json`. | |
| 206 | 211 | 7. Everything else each unit's `setup` names: Vectorize, the dispatch | |
| ⋯ | |||
| 303 | 308 | resetting them, no free capacity, a container that stopped) and ones to | |
| 304 | 309 | read. | |
| 305 | 310 | ||
| 311 | + | ## Agents' computers | |
| 312 | + | ||
| 313 | + | Workspace agents' [own computers](/guides/agents/#its-computer) run on the | |
| 314 | + | same runner image, in a fourth Containers class, `AgentComputer` | |
| 315 | + | (`services/runner/wrangler.jsonc`, `standard-1`, 20 instances to start): | |
| 316 | + | one Durable Object per agent, named `computer:<agent id>`, whose container | |
| 317 | + | runs the runner binary in `MODE=computer` and serves the object over HTTP | |
| 318 | + | for as long as the computer is awake (`crates/runner/src/computer.rs`, | |
| 319 | + | `services/runner/src/computer.ts`). The agents service reaches it through | |
| 320 | + | its `RUNNER` binding, and the API through `AGENTS`. | |
| 321 | + | ||
| 322 | + | Saved homes live in the R2 bucket `g1t-agent-homes`, one `homes/<agent | |
| 323 | + | id>.tar.zst` each, uploaded in parts as the container streams them. The | |
| 324 | + | binding to it is **off** in `services/runner/wrangler.jsonc` until the | |
| 325 | + | bucket exists, because a deploy with a binding to a missing bucket fails. | |
| 326 | + | Without it, computers run but forget their home every time they sleep, and | |
| 327 | + | each Computer tab says the disk isn't attached yet. To turn it on: | |
| 328 | + | ||
| 329 | + | 1. Create the bucket and its lifecycle rule (abandoned multipart uploads | |
| 330 | + | go after a day): | |
| 331 | + | ||
| 332 | + | ```sh | |
| 333 | + | npx wrangler r2 bucket create g1t-agent-homes | |
| 334 | + | npx wrangler r2 bucket lifecycle add g1t-agent-homes abort-uploads homes/ --abort-multipart-days 1 | |
| 335 | + | ``` | |
| 336 | + | ||
| 337 | + | 2. Uncomment the `r2_buckets` block in `services/runner/wrangler.jsonc` | |
| 338 | + | (`HOMES` → `g1t-agent-homes`) and deploy the runner. | |
| 339 | + | ||
| 340 | + | An archived agent's home is deleted by the object itself 30 days later; | |
| 341 | + | nothing else expires in the bucket. Reset deletes the agent's object at | |
| 342 | + | once. | |
| 343 | + | ||
| 306 | 344 | ## Rolling back | |
| 307 | 345 | ||
| 308 | 346 | - **One unit, at once:** `npx wrangler rollback` in its folder. Revert the | |
| 42 | 42 | runs a job or an agent run, and **Offline** when it has not polled for 90 | |
| 43 | 43 | seconds. When a service does not answer, only its part of the page says so. | |
| 44 | 44 | ||
| 45 | − | A runner in the desktop app, sessions that persist on a runner between | |
| 46 | − | tasks, and an official agent image are coming, and the page labels them | |
| 47 | − | so. | |
| 45 | + | Sessions that persist are here for workspace agents: each has | |
| 46 | + | [a computer of its own](/guides/agents/#its-computer) on g1t cloud, whose | |
| 47 | + | home stays between sessions and which sleeps when idle; the page says so | |
| 48 | + | under **Agents' computers and more**. Pinning an agent's computer to one of | |
| 49 | + | your own runners, a runner in the desktop app, and an official agent image | |
| 50 | + | are coming, and the page labels them so. | |
| 48 | 51 | ||
| 49 | 52 | ## Add a runner | |
| 50 | 53 |
| 151 | 151 | | g1t agent rate, your own model key | The same, on runs that use [your own provider](/guides/models/) | — | $0.25, from Oct 22, 2026 | | |
| 152 | 152 | | [AI Gateway](/guides/ai-gateway/) | A request | What the provider charged | The model's list price per token: free of markup during beta | | |
| 153 | 153 | | Sandbox time (agents, workflows, the merge queue) | Second | About $0.001 a minute | About $0.0012 a minute | | |
| 154 | + | | [An agent's computer](#agents-computers), while awake | Second | The same as a sandbox second | The same as a sandbox second; its 5 GB of disk is included | | |
| 154 | 155 | | [Larger machines](#workflow-jobs-on-larger-machines) for workflow jobs (`g1t-2core`, `g1t-4core`) | Second | About 2.8 and 5.1 times a sandbox second | Cost + 20% | | |
| 155 | 156 | | Deploy builds | Second | About $0.001 a minute | About $0.0012 a minute | | |
| 156 | 157 | | App requests | Million | $0.30 | $0.36 | | |
| ⋯ | |||
| 438 | 439 | counted here: [Deployments](/guides/deployments/) charges them by the | |
| 439 | 440 | second, from the first, under **Builds**. | |
| 440 | 441 | ||
| 442 | + | ### Agents' computers | |
| 443 | + | ||
| 444 | + | A workspace agent's [own computer](/guides/agents/#its-computer) is a | |
| 445 | + | sandbox that keeps its home. Its time is sandbox time, priced the same, for | |
| 446 | + | every second it is awake: from the moment it wakes (restoring its home | |
| 447 | + | included) to the moment it has been saved and stops. Asleep it costs | |
| 448 | + | nothing. Each stretch awake is one line on the statement, such as | |
| 449 | + | *@margo's computer, awake: 24m 10s of sandbox time*, under the agent and | |
| 450 | + | whoever asked for the session that woke it, so it shows in that agent's | |
| 451 | + | share of [Spend](/guides/agents/#budgets). | |
| 452 | + | ||
| 453 | + | Its disk, 5 GB, is included with the agent: there is no charge for it, | |
| 454 | + | and it is a hard cap rather than a price. Waking a computer is admitted | |
| 455 | + | the way an agent run is, so a paused workspace, or one past its spend | |
| 456 | + | limit, is refused. | |
| 457 | + | ||
| 441 | 458 | ### Workflow jobs on larger machines | |
| 442 | 459 | ||
| 443 | 460 | A workflow job whose `runs-on` names a [larger machine](/guides/actions/#machine-sizes) | |
| 384 | 384 | | [`message`](/reference/api/pull-requests/message-agent/) | Send the agent working on a pull request a message, received at its next step. g1t sends a `question` or a `handoff`, with its own pull request as `from_number`. | `repo`, `number`, `body` | `agents:run` | | |
| 385 | 385 | | [`answer`](/reference/api/pull-requests/answer-message/) | Answer a question or a handoff by the message's id; `decline` a handoff that is not yours. The answer reaches the asking agent at its next step. | `repo`, `id`, `body` | `agents:run` | | |
| 386 | 386 | | [`take_messages`](/reference/api/pull-requests/take-messages/) | For g1t at work: the messages it has not seen yet, each returned once. | `repo`, `number` | `agents:run` | | |
| 387 | + | | [`computer`](/reference/api/agents-computers/get-agent-computer/) | A workspace agent's [own computer](/guides/agents/#its-computer): its `status` (state, disk, saved home, where it runs), recent `commands`, and `can_manage`. Members; a personal agent's only its member and the owners. | `workspace`, `agent` | `agents:run` | | |
| 388 | + | | [`wake_computer`](/reference/api/agents-computers/wake-agent-computer/) | Wake it: its home is restored and its time is metered until it sleeps. Owners, or a personal agent's member. `payment_required` when the plan refuses compute. | `workspace`, `agent` | `agents:run` | | |
| 389 | + | | [`sleep_computer`](/reference/api/agents-computers/sleep-agent-computer/) | Save its home and stop it. `conflict` while a command runs, or when the home is over its 5 GB cap. | `workspace`, `agent` | `agents:run` | | |
| 390 | + | | [`reset_computer`](/reference/api/agents-computers/reset-agent-computer/) | Wipe its home and command history; memory and artifacts are kept. | `workspace`, `agent` | `agents:run` | | |
| 391 | + | | [`computer_commands`](/reference/api/agents-computers/list-agent-computer-commands/) | The commands it ran most recently, newest first, with output cut at 64 KB. | `workspace`, `agent` | `agents:run` | | |
| 387 | 392 | ||
| 388 | − | See [talk to agents](/guides/talking-to-agents/). | |
| 393 | + | See [talk to agents](/guides/talking-to-agents/), and | |
| 394 | + | [its computer](/guides/agents/#its-computer) for what the computer is. | |
| 389 | 395 | ||
| 390 | 396 | ## `plan` | |
| 391 | 397 |
Binary or large file; its contents are not shown.
| 9 | 9 | import type { RunnersAction, RunnersPageData } from "../lib/runners.server"; | |
| 10 | 10 | import { Groups, NewRunner, RunnerRow, RunnerSettingsForm, STATUS } from "./runners"; | |
| 11 | 11 | import { EmptyState, ErrorText, TimeAgo } from "./ui"; | |
| 12 | + | import { Badge } from "./ui/badge"; | |
| 12 | 13 | import { Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip"; | |
| 13 | 14 | ||
| 14 | 15 | /** The most of what runs on g1t's cloud the card lists before saying how many more. */ | |
| ⋯ | |||
| 179 | 180 | icon={<Cloud size={15} />} | |
| 180 | 181 | title="g1t cloud" | |
| 181 | 182 | tag={<span className="rounded-full bg-raised px-2 py-0.5 text-xs text-fg-soft">Managed by g1t</span>} | |
| 182 | − | about="A fresh sandbox for every agent run and workflow job, stopped when it ends. Billed by the second at the price below." | |
| 183 | + | about="A fresh sandbox for every agent run and workflow job, stopped when it ends; workspace agents keep a computer that sleeps when idle. Billed by the second at the price below." | |
| 183 | 184 | headline={ | |
| 184 | 185 | <div className="flex items-baseline gap-2"> | |
| 185 | 186 | <span className="text-3xl font-semibold tracking-tight tabular-nums">{running ?? "–"}</span> | |
| ⋯ | |||
| 338 | 339 | <Groups groups={data.groups} repositories={data.repositories} manage action={action} /> | |
| 339 | 340 | </Section> | |
| 340 | 341 | ||
| 341 | − | <Section title="Coming to runners"> | |
| 342 | + | <Section title="Agents' computers and more"> | |
| 342 | 343 | <ul className="divide-y divide-line rounded-2xl border border-line bg-surface"> | |
| 343 | − | <ComingRow icon={<Cpu size={15} />} title="Sessions that persist"> | |
| 344 | − | An agent keeps its runner's disk between tasks, its checkouts, caches and notes, and picks up where it left off. | |
| 344 | + | <ComingRow icon={<Cpu size={15} />} title="Sessions that persist" live> | |
| 345 | + | Each workspace agent has a computer of its own on g1t cloud: its home, clones, caches and notes stay between sessions, and it sleeps when idle. Its page is the | |
| 346 | + | agent's Computer tab. Pinning it to one of your runners is coming. | |
| 345 | 347 | </ComingRow> | |
| 346 | 348 | <ComingRow icon={<Boxes size={15} />} title="An official agent image"> | |
| 347 | 349 | One image with git, Node and the agent's tools, so agent work runs on any runner with Docker without an image of your own. | |
| ⋯ | |||
| 365 | 367 | ); | |
| 366 | 368 | } | |
| 367 | 369 | ||
| 368 | − | function ComingRow({ icon, title, children }: { icon: ReactNode; title: string; children: ReactNode }) { | |
| 370 | + | /** One thing runners do or will do: live, or marked Coming. */ | |
| 371 | + | function ComingRow({ icon, title, live = false, children }: { icon: ReactNode; title: string; live?: boolean; children: ReactNode }) { | |
| 369 | 372 | return ( | |
| 370 | 373 | <li className="flex items-start gap-3 px-4 py-3"> | |
| 371 | 374 | <span className="mt-0.5 text-muted">{icon}</span> | |
| 372 | 375 | <div className="min-w-0 grow"> | |
| 373 | 376 | <p className="flex items-center gap-2 text-sm font-medium"> | |
| 374 | 377 | {title} | |
| 375 | − | <Coming /> | |
| 378 | + | {live ? <Badge tone="success">Live</Badge> : <Coming />} | |
| 376 | 379 | </p> | |
| 377 | 380 | <p className="mt-0.5 text-sm text-muted">{children}</p> | |
| 378 | 381 | </div> | |
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
Binary or large file; its contents are not shown.
This change is too large to show in full.