agentic-runner 3.26.1__tar.gz → 3.27.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/PKG-INFO +4 -4
  2. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/README.md +2 -2
  3. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/pyproject.toml +1 -1
  4. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/__init__.py +1 -1
  5. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/cli.py +52 -34
  6. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/service.py +18 -2
  7. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/skills/agentic-runner-setup/SKILL.md +10 -7
  8. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/workstation.py +65 -59
  9. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/.gitignore +0 -0
  10. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/LICENSE +0 -0
  11. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/activities.py +0 -0
  12. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/attempts.py +0 -0
  13. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/auth_mode.py +0 -0
  14. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/build.py +0 -0
  15. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/callback.py +0 -0
  16. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/child_watcher.py +0 -0
  17. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/cli_floor.py +0 -0
  18. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/config.py +0 -0
  19. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/credentials.py +0 -0
  20. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/egress.py +0 -0
  21. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/harness_self_test.py +0 -0
  22. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/heartbeat_link.py +0 -0
  23. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/hooks.py +0 -0
  24. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/host_store.py +0 -0
  25. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/integrations/__init__.py +0 -0
  26. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/integrations/git/__init__.py +0 -0
  27. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/integrations/git/contracts.py +0 -0
  28. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/integrations/git/evidence.py +0 -0
  29. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/integrations/git/fake_workspace.py +0 -0
  30. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/integrations/git/workspace.py +0 -0
  31. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/integrations/github/__init__.py +0 -0
  32. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/integrations/github/auth.py +0 -0
  33. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/integrations/github/fake_client.py +0 -0
  34. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/integrations/github/gh_client.py +0 -0
  35. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/integrations/oauth/__init__.py +0 -0
  36. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/integrations/oauth/fake_provider.py +0 -0
  37. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/launch.py +0 -0
  38. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/lifecycle.py +0 -0
  39. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/llm_contracts.py +0 -0
  40. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/llm_proxy.py +0 -0
  41. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/mcp.py +0 -0
  42. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/message_store.py +0 -0
  43. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/oauth_connectors.py +0 -0
  44. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/pool_key.py +0 -0
  45. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/private_state.py +0 -0
  46. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/py.typed +0 -0
  47. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/recipient_key_secret.py +0 -0
  48. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/registration.py +0 -0
  49. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/runner_limit.py +0 -0
  50. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/runtime/__init__.py +0 -0
  51. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/runtime/verifier_command.py +0 -0
  52. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/sealed_box.py +0 -0
  53. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/sign_in.py +0 -0
  54. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/skill.py +0 -0
  55. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/testing/__init__.py +0 -0
  56. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/testing/__main__.py +0 -0
  57. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/testing/control_plane.py +0 -0
  58. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/testing/plugin.py +0 -0
  59. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/testing/test_conformance.py +0 -0
  60. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/testing/workflow.py +0 -0
  61. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/tiny_http.py +0 -0
  62. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/triage_activities.py +0 -0
  63. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/usage_windows.py +0 -0
  64. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/user_sources.py +0 -0
  65. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/workers/__init__.py +0 -0
  66. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/workers/_runtime_support.py +0 -0
  67. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/workers/acp_runtime.py +0 -0
  68. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/workers/agent_runtime.py +0 -0
  69. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/workers/claude_runtime.py +0 -0
  70. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/workers/claude_sign_in.py +0 -0
  71. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/workers/codex_runtime.py +0 -0
  72. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/workers/command_policy.py +0 -0
  73. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/workers/contract_isolation.py +0 -0
  74. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/workers/fastapi_client.py +0 -0
  75. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/workers/harness_logins.py +0 -0
  76. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/workers/harness_outcome.py +0 -0
  77. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/workers/harness_usage.py +0 -0
  78. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/workers/mcp_config.py +0 -0
  79. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/workers/settings.py +0 -0
  80. {agentic_runner-3.26.1 → agentic_runner-3.27.0}/src/agentic_runner/workers/skills.py +0 -0
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: agentic-runner
3
- Version: 3.26.1
3
+ Version: 3.27.0
4
4
  Summary: The Agentic OS Runner: an activity-only Temporal executor for workspaces, Agent Runtimes and verb seams
5
5
  License-Expression: AGPL-3.0-only
6
6
  License-File: LICENSE
7
7
  Requires-Python: >=3.12
8
- Requires-Dist: agentic-runner-contracts==3.26.1
8
+ Requires-Dist: agentic-runner-contracts==3.27.0
9
9
  Requires-Dist: cryptography<51,>=50
10
10
  Requires-Dist: httpx<1.0,>=0.27
11
11
  Requires-Dist: pydantic-settings<3.0,>=2.0
@@ -46,8 +46,8 @@ It ships as `ghcr.io/qtsone/agentic-runner` (`Dockerfile.runner` at the reposito
46
46
  root: Python, git, `codex`, `claude`, nothing else) and installs with
47
47
  `charts/agentic-runner`.
48
48
 
49
- On a workstation it is a per-user login agent, one per Organisation:
50
- `agentic-runner install | start | stop | status <org>` (LaunchAgent, systemd user unit or
49
+ On a workstation it is a per-user login agent, one per Runner:
50
+ `agentic-runner install | start | stop | status <name>` (LaunchAgent, systemd user unit or
51
51
  logon task; never `sudo`), with Credential References in the OS credential store.
52
52
 
53
53
  Licensed under AGPL-3.0-only.
@@ -27,8 +27,8 @@ It ships as `ghcr.io/qtsone/agentic-runner` (`Dockerfile.runner` at the reposito
27
27
  root: Python, git, `codex`, `claude`, nothing else) and installs with
28
28
  `charts/agentic-runner`.
29
29
 
30
- On a workstation it is a per-user login agent, one per Organisation:
31
- `agentic-runner install | start | stop | status <org>` (LaunchAgent, systemd user unit or
30
+ On a workstation it is a per-user login agent, one per Runner:
31
+ `agentic-runner install | start | stop | status <name>` (LaunchAgent, systemd user unit or
32
32
  logon task; never `sudo`), with Credential References in the OS credential store.
33
33
 
34
34
  Licensed under AGPL-3.0-only.
@@ -10,7 +10,7 @@ dependencies = [
10
10
  # Exactly this release's contracts: the two ship as one version, and an unpinned
11
11
  # requirement let `uv tool upgrade` keep an older contracts wheel the Runner cannot
12
12
  # import from (QTS-1473). `scripts/set-version.py` moves it with the version.
13
- "agentic-runner-contracts==3.26.1",
13
+ "agentic-runner-contracts==3.27.0",
14
14
  # Imported directly by `registration.py` (the Ed25519 identity that signs every
15
15
  # heartbeat); already present transitively through pyjwt[crypto], declared because
16
16
  # we import it.
@@ -7,6 +7,6 @@ stay on the platform; this package imports none of them, and a CI partition test
7
7
  (``tests/test_package_partition.py``) fails the build if that changes.
8
8
  """
9
9
 
10
- __version__ = "3.26.1"
10
+ __version__ = "3.27.0"
11
11
 
12
12
  __all__ = ["__version__"]
@@ -11,9 +11,10 @@ namespace and queue this process was assigned. It is idempotent by state file --
11
11
  restart re-reads what is already there rather than registering a second Runner against
12
12
  the Organisation's cap.
13
13
 
14
- ``install | start | stop | status <org>`` and ``credential set`` are the workstation
15
- Runner (PRD issue 47, ``workstation.py``): one login agent per Organisation, managed by
16
- the user who hosts it, with no ``sudo`` anywhere.
14
+ ``install | start | stop | status <name>`` and ``credential set`` are the workstation
15
+ Runner (PRD issue 47, ``workstation.py``): one login agent per Runner, managed by the user
16
+ who hosts it, with no ``sudo`` anywhere. ``<name>`` is the Runner's, the one the console
17
+ lists it under (QTS-1773).
17
18
 
18
19
  ``sign-in [claude|codex]`` gives a person's own Runner their LLM access: their subscription,
19
20
  through the vendor's own sign-in in this terminal, or an API key stored in the Runner's
@@ -102,6 +103,18 @@ __all__ = [
102
103
  STATE_DIR_ENV = "AGENTIC_RUNNER_STATE_DIR"
103
104
 
104
105
 
106
+ _NAME_HELP = (
107
+ "this Runner's name: the console lists it under this name, and every command on this "
108
+ "machine takes it"
109
+ )
110
+
111
+
112
+ def _old_org_flag(parser: argparse.ArgumentParser) -> None:
113
+ # A login agent written before QTS-1773 runs `run --org <name>` and is not rewritten
114
+ # until its next `install`, so the old spelling keeps parsing, unlisted.
115
+ parser.add_argument("--org", dest="name", help=argparse.SUPPRESS)
116
+
117
+
105
118
  def _state_dir() -> Path:
106
119
  return load_config().state_dir
107
120
 
@@ -158,14 +171,15 @@ def main(argv: Sequence[str] | None = None) -> int:
158
171
  )
159
172
 
160
173
  run = subcommands.add_parser("run", help="register if needed, then heartbeat and poll for work")
161
- run.add_argument("--org", default=None, help="run an installed workstation Organisation")
174
+ run.add_argument("--name", default=None, help="run an installed workstation Runner")
175
+ _old_org_flag(run)
162
176
  run.add_argument("--root", default=None, type=Path, help=argparse.SUPPRESS)
163
177
  run.add_argument("--login-agent", action="store_true", help=argparse.SUPPRESS)
164
178
 
165
179
  install = subcommands.add_parser(
166
- "install", help="register a workstation Runner for one Organisation (issue 47)"
180
+ "install", help="register a workstation Runner and install its login agent (issue 47)"
167
181
  )
168
- install.add_argument("org")
182
+ install.add_argument("name", help=_NAME_HELP)
169
183
  install.add_argument(
170
184
  "--control-plane", default=os.environ.get(CONTROL_PLANE_ENV), help="control plane URL"
171
185
  )
@@ -195,16 +209,16 @@ def main(argv: Sequence[str] | None = None) -> int:
195
209
  install.add_argument("--root", default=None, type=Path, help="state root (default per OS)")
196
210
  for service_verb in ("start", "stop"):
197
211
  driven = subcommands.add_parser(
198
- service_verb, help=f"{service_verb} one Organisation's login agent"
212
+ service_verb, help=f"{service_verb} one workstation Runner's login agent"
199
213
  )
200
- driven.add_argument("org")
214
+ driven.add_argument("name", help=_NAME_HELP)
201
215
  driven.add_argument("--root", default=None, type=Path)
202
216
 
203
217
  credential = subcommands.add_parser(
204
218
  "credential", help="install a Credential Reference value into this host's store"
205
219
  )
206
220
  credential.add_argument("action", choices=("set",))
207
- credential.add_argument("org")
221
+ credential.add_argument("name", help=_NAME_HELP)
208
222
  credential.add_argument("reference")
209
223
  credential.add_argument("--root", default=None, type=Path)
210
224
 
@@ -219,7 +233,7 @@ def main(argv: Sequence[str] | None = None) -> int:
219
233
  status = subcommands.add_parser(
220
234
  "status", help="print this installation's versions and Recipient Key fingerprint"
221
235
  )
222
- status.add_argument("org", nargs="?", help="a workstation Organisation (issue 47)")
236
+ status.add_argument("name", nargs="?", help="a workstation Runner's name (issue 47)")
223
237
  status.add_argument("--root", default=None, type=Path)
224
238
 
225
239
  sign_in = subcommands.add_parser(
@@ -240,10 +254,11 @@ def main(argv: Sequence[str] | None = None) -> int:
240
254
  "claude_ai: a Claude.ai login (claude auth login --claudeai)",
241
255
  )
242
256
  sign_in.add_argument(
243
- "--org",
257
+ "--name",
244
258
  default=None,
245
- help="the workstation Organisation, when this workstation runs more than one",
259
+ help="the workstation Runner's name, when this workstation runs more than one",
246
260
  )
261
+ _old_org_flag(sign_in)
247
262
  sign_in.add_argument("--root", default=None, type=Path, help=argparse.SUPPRESS)
248
263
 
249
264
  annotate = subcommands.add_parser("annotate", help="attach an annotation to this Work Record")
@@ -332,8 +347,10 @@ def main(argv: Sequence[str] | None = None) -> int:
332
347
  return 1
333
348
  return 0
334
349
  if arguments.command == "run":
335
- if arguments.org:
336
- return workstation.run_process(_org_paths(arguments), login_agent=arguments.login_agent)
350
+ if arguments.name:
351
+ return workstation.run_process(
352
+ _runner_paths(arguments), login_agent=arguments.login_agent
353
+ )
337
354
  return asyncio.run(service.run(attestation=_image_attestation(), install=_run_install()))
338
355
  if arguments.command in {"install", "start", "stop", "credential"}:
339
356
  return _workstation(arguments)
@@ -347,7 +364,9 @@ def main(argv: Sequence[str] | None = None) -> int:
347
364
  )
348
365
  return 0
349
366
  if arguments.command == "status":
350
- lines = workstation.status_lines(_org_paths(arguments)) if arguments.org else status_lines()
367
+ lines = (
368
+ workstation.status_lines(_runner_paths(arguments)) if arguments.name else status_lines()
369
+ )
351
370
  for line in lines:
352
371
  print(line)
353
372
  return 0
@@ -370,28 +389,28 @@ def main(argv: Sequence[str] | None = None) -> int:
370
389
  return _callback(arguments)
371
390
 
372
391
 
373
- def _org_paths(arguments: argparse.Namespace) -> workstation.OrgPaths:
374
- return workstation.OrgPaths(
392
+ def _runner_paths(arguments: argparse.Namespace) -> workstation.RunnerPaths:
393
+ return workstation.RunnerPaths(
375
394
  root=arguments.root or workstation.default_root(),
376
- org=workstation.validate_org(arguments.org),
395
+ name=workstation.validate_name(arguments.name),
377
396
  )
378
397
 
379
398
 
380
399
  def _workstation(arguments: argparse.Namespace) -> int:
381
- paths = _org_paths(arguments)
400
+ paths = _runner_paths(arguments)
382
401
  try:
383
402
  if arguments.command == "install":
384
403
  return _install(arguments, paths)
385
404
  if arguments.command == "start":
386
405
  workstation.start(paths)
387
- print(f"started {paths.org}")
406
+ print(f"started {paths.name}")
388
407
  return 0
389
408
  if arguments.command == "stop":
390
409
  workstation.stop(paths)
391
- print(f"stopped {paths.org}; every other Organisation's Runner keeps polling")
410
+ print(f"stopped {paths.name}; every other Runner on this machine keeps polling")
392
411
  return 0
393
412
  # The value arrives on stdin so it is never in argv or shell history.
394
- store = open_workstation_store(paths.org, fallback=paths.credentials)
413
+ store = open_workstation_store(paths.name, fallback=paths.credentials)
395
414
  store.put(arguments.reference, sys.stdin.read().strip())
396
415
  print(f"{arguments.reference} stored in the {store.kind.value} store")
397
416
  return 0
@@ -461,26 +480,26 @@ def _sign_in(arguments: argparse.Namespace) -> int:
461
480
  )
462
481
  return 2
463
482
  store: KeyStore
464
- if arguments.org or not _in_container():
483
+ if arguments.name or not _in_container():
465
484
  try:
466
- paths = _sign_in_org(arguments)
485
+ paths = _sign_in_paths(arguments)
467
486
  except ValueError as error:
468
487
  print(error, file=sys.stderr)
469
488
  return 2
470
489
  os.environ.update(
471
490
  workstation.run_environment(paths, workstation.WorkstationSettings.load(paths))
472
491
  )
473
- store = open_workstation_store(paths.org, fallback=paths.credentials)
492
+ store = open_workstation_store(paths.name, fallback=paths.credentials)
474
493
  else:
475
494
  store = service.own_store(load_config())
476
495
  return asyncio.run(service.sign_in(arguments.runtime, store=store, method=arguments.method))
477
496
 
478
497
 
479
- def _sign_in_org(arguments: argparse.Namespace) -> workstation.OrgPaths:
480
- """``--org``, or the one Organisation this workstation runs -- no id to type."""
498
+ def _sign_in_paths(arguments: argparse.Namespace) -> workstation.RunnerPaths:
499
+ """``--name``, or the one Runner this workstation runs -- no id to type."""
481
500
 
482
- if arguments.org:
483
- return _org_paths(arguments)
501
+ if arguments.name:
502
+ return _runner_paths(arguments)
484
503
  root = arguments.root or workstation.default_root()
485
504
  installed = (
486
505
  sorted(path.name for path in root.iterdir() if (path / "workstation.json").is_file())
@@ -491,12 +510,12 @@ def _sign_in_org(arguments: argparse.Namespace) -> workstation.OrgPaths:
491
510
  raise ValueError(
492
511
  "no workstation Runner is installed here"
493
512
  if not installed
494
- else f"this workstation runs {', '.join(installed)}: name one with --org"
513
+ else f"this workstation runs {', '.join(installed)}: name one with --name"
495
514
  )
496
- return workstation.OrgPaths(root=root, org=installed[0])
515
+ return workstation.RunnerPaths(root=root, name=installed[0])
497
516
 
498
517
 
499
- def _install(arguments: argparse.Namespace, paths: workstation.OrgPaths) -> int:
518
+ def _install(arguments: argparse.Namespace, paths: workstation.RunnerPaths) -> int:
500
519
  if not arguments.control_plane:
501
520
  print(f"--control-plane (or {CONTROL_PLANE_ENV}) is required", file=sys.stderr)
502
521
  return 2
@@ -518,7 +537,6 @@ def _install(arguments: argparse.Namespace, paths: workstation.OrgPaths) -> int:
518
537
  else None
519
538
  )
520
539
  settings = workstation.WorkstationSettings(
521
- org=paths.org,
522
540
  control_plane_url=arguments.control_plane,
523
541
  temporal_address=arguments.temporal_address,
524
542
  temporal_tls=not arguments.temporal_plaintext,
@@ -549,7 +567,7 @@ def _install(arguments: argparse.Namespace, paths: workstation.OrgPaths) -> int:
549
567
  return 0
550
568
 
551
569
 
552
- def _acp_cli_kinds(flag: str | None, paths: workstation.OrgPaths) -> str:
570
+ def _acp_cli_kinds(flag: str | None, paths: workstation.RunnerPaths) -> str:
553
571
  # A reinstall to pick up a new PATH or retry a token must not turn ACP off (QTS-1355).
554
572
  if flag is not None:
555
573
  return workstation.parse_acp_cli_kinds(flag)
@@ -250,7 +250,7 @@ _VERIFIER_ACTIVITY_BUDGET_SECONDS = 20 * 60
250
250
  # chart's value and this must move together).
251
251
  _SHUTDOWN_HEADROOM_SECONDS = 60
252
252
 
253
- # What `agentic-runner status <org>` reads (PRD issue 47): the live pid, and a file the
253
+ # What `agentic-runner status <name>` reads (PRD issue 47): the live pid, and a file the
254
254
  # process touches on every acknowledged heartbeat, whose mtime is the heartbeat age.
255
255
  PIDFILE_NAME = "runner.pid"
256
256
  HEARTBEAT_STAMP_NAME = "last-heartbeat"
@@ -849,6 +849,9 @@ class ControlPlaneStream:
849
849
  # control plane on 3.25 named them, and the LLM access report is sent only after.
850
850
  _llm_contracts: list[ContractLlmTerms] | None = None
851
851
  _pool: PoolTerms | None = None
852
+ # QTS-1773: the control plane's contracts version, from its ack; None until an ack from
853
+ # one on 3.27 or later, the first to send it and to parse `RunnerInstall.name`.
854
+ _control_plane_contracts: str | None = None
852
855
  _last_seen: tuple[float, datetime] | None = None
853
856
 
854
857
  def _observe_sleep(self, now: datetime) -> None:
@@ -976,6 +979,17 @@ class ControlPlaneStream:
976
979
  for terms in self._llm_contracts
977
980
  ]
978
981
 
982
+ def _install_report(self) -> RunnerInstall | None:
983
+ """Where a command reaches this Runner, sent once an ack named the Contracts -- a
984
+ control plane below 3.25 refuses the field -- and with its name only once an ack
985
+ came from a control plane on 3.27, since one below refuses that key (QTS-1773)."""
986
+
987
+ if self.install is None or self._llm_contracts is None:
988
+ return None
989
+ if self._control_plane_contracts is None:
990
+ return self.install.model_copy(update={"name": None})
991
+ return self.install
992
+
979
993
  def _credential_report(self) -> list[CredentialValidity]:
980
994
  """Per Contract the last ack named, whether each reference would resolve (§7).
981
995
 
@@ -1037,7 +1051,7 @@ class ControlPlaneStream:
1037
1051
  oauth_outcomes=self.oauth.take_outcomes() if self.oauth else [],
1038
1052
  runner_limit=self.runner_limit,
1039
1053
  llm_access=self._llm_access_report(),
1040
- install=self.install if self._llm_contracts is not None else None,
1054
+ install=self._install_report(),
1041
1055
  pool_key_fingerprint=self.pool_key_fingerprint if self._pool is not None else None,
1042
1056
  )
1043
1057
  ack = await self.client.heartbeat(self.state, envelope)
@@ -1065,6 +1079,8 @@ class ControlPlaneStream:
1065
1079
  self._manifests = list(ack.credential_manifests)
1066
1080
  self._take_llm_contracts(ack.llm_contracts)
1067
1081
  self._take_pool(ack.pool)
1082
+ if ack.contracts_version is not None:
1083
+ self._control_plane_contracts = ack.contracts_version
1068
1084
  await self._sync_llm_slots()
1069
1085
  if ack.runner_token is not None:
1070
1086
  self.runner_token = ack.runner_token
@@ -8,7 +8,8 @@ license: AGPL-3.0-only
8
8
 
9
9
  You help a person who has never run a Runner. A **Runner** is the program that does their
10
10
  Agents' work: it runs Codex or Claude Code on a machine they choose and connects out to the
11
- Agentic OS control plane. It belongs to one **Organisation** (the company the work is for).
11
+ Agentic OS control plane. It belongs to one **Organisation** (the company the work is for),
12
+ and has a **name** the person chose for it in the console.
12
13
 
13
14
  The install documents in the `qtsone/agentic-runner` repository are the source for every
14
15
  command. Do not reconstruct a command from memory: open the section named in each step and
@@ -18,7 +19,9 @@ follow it.
18
19
 
19
20
  The prompt they pasted from the console holds these. Ask for any that is missing.
20
21
 
21
- - **Organisation**: a short local name for it, lowercase letters, digits and `-` (`acme`).
22
+ - **Runner name**: the name the person gave the Runner in the console, lowercase letters,
23
+ digits and `-` (`alice-laptop`). A prompt from an older console calls it **Organisation**;
24
+ it is the same value.
22
25
  - **Control plane URL**: the Runner's `controlPlane.url`, copied from the console's
23
26
  Runners page. It is the only control plane address you use, and only as a value you
24
27
  pass to the Runner. Never call it or any other control plane address yourself.
@@ -75,13 +78,13 @@ missing.
75
78
 
76
79
  **This machine.** Follow
77
80
  https://github.com/qtsone/agentic-runner/blob/main/docs/workstation.md#install. Install the
78
- Runner, then show the person the command that registers it for the Organisation and ask
81
+ Runner, then show the person the command that registers it under its name and ask
79
82
  them to run it in their own terminal. The Runner asks them for the Runner Registration Token there,
80
83
  without showing it:
81
84
 
82
85
  ```sh
83
86
  uv tool install agentic-runner
84
- agentic-runner install <org> --control-plane <control-plane-url>
87
+ agentic-runner install <name> --control-plane <control-plane-url>
85
88
  ```
86
89
 
87
90
  You run the first line. Do not run the second yourself: wait until the person says it
@@ -113,7 +116,7 @@ agentic-runner sign-in claude
113
116
  ```
114
117
 
115
118
  `codex` in place of `claude` for Codex; with no argument it asks about each. Add
116
- `--org <org>` only if this machine runs Runners for several Organisations. On Docker it is
119
+ `--name <name>` only if this machine runs more than one Runner. On Docker it is
117
120
  `docker exec -it <container> agentic-runner sign-in claude`, on Kubernetes
118
121
  `kubectl exec -it <pod> -c runner -- agentic-runner sign-in claude`.
119
122
 
@@ -130,7 +133,7 @@ it: it uses the Organisation's keys, which its admin puts in the Runner's own st
130
133
  On this machine, run every 10 seconds, for at most 3 minutes:
131
134
 
132
135
  ```sh
133
- agentic-runner status <org>
136
+ agentic-runner status <name>
134
137
  ```
135
138
 
136
139
  The Runner is online when `process` says `running` and `heartbeat` shows a number of
@@ -141,7 +144,7 @@ it" section. If 3 minutes pass, stop and show the last output and the "Check it"
141
144
 
142
145
  One screen, nothing more:
143
146
 
144
- - the way, the Organisation and the Runner's identity line from `status`;
147
+ - the way, the Runner's name and its identity line from `status`;
145
148
  - whether the LLM credential is in place, or the one thing the person still does in the
146
149
  console;
147
150
  - the `next` line `status` prints: where in the console to see the Runner and give it work.
@@ -1,12 +1,16 @@
1
- """The workstation Runner: one login agent per Organisation (PRD issue 47, map ticket 23).
1
+ """The workstation Runner: one login agent per Runner (PRD issue 47, map ticket 23).
2
2
 
3
- ``agentic-runner install | start | stop | status <org>``. Everything a CI-runner
3
+ ``agentic-runner install | start | stop | status <name>``. Everything a CI-runner
4
4
  precedent does on a developer machine and nothing a daemon would need:
5
5
 
6
- * **One process per Organisation** (23 item 3), each with its own state directory,
7
- identity, namespace, Runner Token, hooks, credential store and Workspaces under
8
- ``<root>/<org>/``. A contractor with two clients runs two. There is no supervisor over
9
- N Organisations -- that is the "one Runner straddling Organisations" 12 A6 rejected.
6
+ * **One process per Runner** (23 item 3), each with its own state directory, identity,
7
+ namespace, Runner Token, hooks, credential store and Workspaces under ``<root>/<name>/``.
8
+ A contractor with two clients runs two. There is no supervisor over N Runners -- that
9
+ is the "one Runner straddling Organisations" 12 A6 rejected.
10
+ * **The name is the Runner's** (QTS-1773): the console lists the Runner under the name it
11
+ was installed as, and every local command takes it. It was an Organisation label before,
12
+ so the name a person chose on /me/runners read as an Organisation; an install made then
13
+ keeps its directory, login agent and keychain entries, all keyed by the same string.
10
14
  * **A login agent, never a system daemon** (23 item 1): a LaunchAgent in
11
15
  ``~/Library/LaunchAgents`` on macOS, a systemd *user* unit (with linger) on Linux, a
12
16
  per-user logon task on Windows. No ``sudo`` anywhere: the login keychain is unreachable
@@ -18,8 +22,8 @@ precedent does on a developer machine and nothing a daemon would need:
18
22
  under a harness root -- the per-Contract ``CODEX_HOME`` / ``CLAUDE_CONFIG_DIR`` belongs
19
23
  to the login the funder created there (issues 30, 31).
20
24
  * **``isolation: none``** (17 A2): no root and no uid switch, so the control plane routes
21
- at most one Contract at a time here (issue 42), which one Organisation per process and
22
- one active Contract per (Organisation, User Profile) pair already implied.
25
+ at most one Contract at a time here (issue 42), which one Contract per personal Runner
26
+ already implied.
23
27
  """
24
28
 
25
29
  from __future__ import annotations
@@ -54,6 +58,7 @@ from agentic_runner.registration import load_state
54
58
  from agentic_runner.service import HEARTBEAT_STAMP_NAME, PIDFILE_NAME
55
59
  from agentic_runner.workers.acp_runtime import ACP_BRIDGES
56
60
  from agentic_runner_contracts.runner_registration import (
61
+ RUNNER_NAME_PATTERN,
57
62
  CliVersion,
58
63
  EgressPosture,
59
64
  HostAttestation,
@@ -71,7 +76,7 @@ __all__ = [
71
76
  "CLI_NAMES",
72
77
  "ROOT_ENV",
73
78
  "CliMissingError",
74
- "OrgPaths",
79
+ "RunnerPaths",
75
80
  "ServiceDefinition",
76
81
  "WorkstationSettings",
77
82
  "cli_versions",
@@ -88,12 +93,11 @@ __all__ = [
88
93
  "start",
89
94
  "status_lines",
90
95
  "stop",
91
- "validate_org",
96
+ "validate_name",
92
97
  ]
93
98
 
94
99
  ROOT_ENV: Final = "AGENTIC_RUNNER_WORKSTATION_ROOT"
95
100
 
96
- _ORG = re.compile(r"^[a-z0-9][a-z0-9-]{0,31}$")
97
101
  _LABEL_PREFIX: Final = "agentic-runner"
98
102
 
99
103
  Run = Callable[..., subprocess.CompletedProcess[str]]
@@ -103,18 +107,19 @@ class CliMissingError(RuntimeError):
103
107
  pass
104
108
 
105
109
 
106
- def validate_org(org: str) -> str:
110
+ def validate_name(name: str) -> str:
107
111
  """One path segment, one launchd label, one systemd instance name -- all at once."""
108
112
 
109
- if not _ORG.fullmatch(org):
113
+ if not re.fullmatch(RUNNER_NAME_PATTERN, name):
110
114
  raise ValueError(
111
- f"Organisation name {org!r} must be 1-32 of lowercase letters, digits and '-'"
115
+ f"Runner name {name!r} must be 1-32 of lowercase letters, digits and '-', "
116
+ "starting with a letter or digit"
112
117
  )
113
- return org
118
+ return name
114
119
 
115
120
 
116
121
  def default_root(*, platform: str = sys.platform, environ: Mapping[str, str] = os.environ) -> Path:
117
- """Where every Organisation's directory lives, per the OS's per-user convention."""
122
+ """Where every Runner's directory lives, per the OS's per-user convention."""
118
123
 
119
124
  if environ.get(ROOT_ENV, "").strip():
120
125
  return Path(environ[ROOT_ENV])
@@ -128,19 +133,19 @@ def default_root(*, platform: str = sys.platform, environ: Mapping[str, str] = o
128
133
 
129
134
 
130
135
  @dataclass(frozen=True)
131
- class OrgPaths:
132
- """``<root>/<org>/`` and everything the process keeps under it."""
136
+ class RunnerPaths:
137
+ """``<root>/<name>/`` and everything the process keeps under it."""
133
138
 
134
139
  root: Path
135
- org: str
140
+ name: str
136
141
 
137
142
  @property
138
143
  def state_dir(self) -> Path:
139
- return self.root / self.org
144
+ return self.root / self.name
140
145
 
141
146
  @property
142
147
  def hooks(self) -> Path:
143
- # Issue 45's path, per map ticket 26: `<state_dir>/<org>/hooks/`.
148
+ # Issue 45's path, per map ticket 26: `<state_dir>/<name>/hooks/`.
144
149
  return self.state_dir / "hooks"
145
150
 
146
151
  @property
@@ -189,7 +194,7 @@ class OrgPaths:
189
194
  tempfile.gettempdir() if sys.platform == "darwin" else ""
190
195
  )
191
196
  if runtime:
192
- return Path(runtime) / f"agentic-runner-{self.org}"
197
+ return Path(runtime) / f"agentic-runner-{self.name}"
193
198
  return self.state_dir / "sockets"
194
199
 
195
200
  def create(self) -> None:
@@ -203,10 +208,10 @@ class WorkstationSettings(BaseModel):
203
208
  """What ``install`` was told, so ``run`` and ``status`` need no flags."""
204
209
 
205
210
  # `ignore`, not `forbid`: only `save` writes this file, and an install made before
206
- # local-agents 01 retired the per-process `cli_kind` still has to `run` and `status`.
211
+ # local-agents 01 retired the per-process `cli_kind`, or before QTS-1773 dropped the
212
+ # `org` its directory already names, still has to `run` and `status`.
207
213
  model_config = ConfigDict(extra="ignore", frozen=True)
208
214
 
209
- org: str
210
215
  control_plane_url: str
211
216
  # A fallback only: `run` uses the address the registration response carries (ADR-0022
212
217
  # §4). An install made before 3.17 saved one and keeps it.
@@ -222,15 +227,15 @@ class WorkstationSettings(BaseModel):
222
227
  # which every `install` rewrites (QTS-1355).
223
228
  acp_cli_kinds: str = ""
224
229
 
225
- def save(self, paths: OrgPaths) -> None:
230
+ def save(self, paths: RunnerPaths) -> None:
226
231
  paths.settings_file.write_text(self.model_dump_json(indent=2), encoding="utf-8")
227
232
 
228
233
  @classmethod
229
- def load(cls, paths: OrgPaths) -> WorkstationSettings:
234
+ def load(cls, paths: RunnerPaths) -> WorkstationSettings:
230
235
  if not paths.settings_file.is_file():
231
236
  raise FileNotFoundError(
232
- f"no Runner is installed for {paths.org!r} under {paths.root}; "
233
- f"run `agentic-runner install {paths.org}` first"
237
+ f"no Runner is installed for {paths.name!r} under {paths.root}; "
238
+ f"run `agentic-runner install {paths.name}` first"
234
239
  )
235
240
  return cls.model_validate_json(paths.settings_file.read_text(encoding="utf-8"))
236
241
 
@@ -262,8 +267,8 @@ def install_channel(
262
267
  return InstallChannel.SYSTEMD_USER
263
268
 
264
269
 
265
- def run_environment(paths: OrgPaths, settings: WorkstationSettings) -> dict[str, str]:
266
- """The environment ``agentic-runner run --org`` gives ``service.run``.
270
+ def run_environment(paths: RunnerPaths, settings: WorkstationSettings) -> dict[str, str]:
271
+ """The environment ``agentic-runner run --name`` gives ``service.run``.
267
272
 
268
273
  Set here rather than in the service definition so one definition format -- a plist,
269
274
  a unit, a task -- stays a one-liner, and the three OSes cannot drift apart.
@@ -285,7 +290,7 @@ def run_environment(paths: OrgPaths, settings: WorkstationSettings) -> dict[str,
285
290
  "TEMPORAL_ADDRESS": settings.temporal_address,
286
291
  "WORKSPACE_ROOT": str(paths.workspaces),
287
292
  "WORKER_STATE_DIR": str(paths.contract_state),
288
- # Ephemeral: one process per Organisation shares the host, so a fixed readiness
293
+ # Ephemeral: one process per Runner shares the host, so a fixed readiness
289
294
  # port inherited from a pod-style environment would collide on the second one.
290
295
  service.READINESS_PORT_ENV: "0",
291
296
  }
@@ -396,16 +401,16 @@ class ServiceDefinition:
396
401
  stop: list[list[str]]
397
402
 
398
403
 
399
- def runner_command(org: str, root: Path) -> list[str]:
404
+ def runner_command(name: str, root: Path) -> list[str]:
400
405
  # The console script as found, not resolved: Homebrew's `bin/agentic-runner` is a
401
406
  # symlink into a versioned Cellar path that the next `brew upgrade` deletes.
402
407
  script = shutil.which("agentic-runner")
403
408
  prefix = [script] if script else [sys.executable, "-m", "agentic_runner.launch"]
404
- return [*prefix, "run", "--org", org, "--root", str(root), "--login-agent"]
409
+ return [*prefix, "run", "--name", name, "--root", str(root), "--login-agent"]
405
410
 
406
411
 
407
412
  def service_definition(
408
- paths: OrgPaths,
413
+ paths: RunnerPaths,
409
414
  settings: WorkstationSettings,
410
415
  *,
411
416
  platform: str = sys.platform,
@@ -415,8 +420,8 @@ def service_definition(
415
420
  command: Sequence[str] | None = None,
416
421
  ) -> ServiceDefinition:
417
422
  home = home or Path.home()
418
- argv = list(command or runner_command(paths.org, paths.root))
419
- name = f"{_LABEL_PREFIX}.{paths.org}"
423
+ argv = list(command or runner_command(paths.name, paths.root))
424
+ name = f"{_LABEL_PREFIX}.{paths.name}"
420
425
  if platform == "darwin":
421
426
  return _launch_agent(paths, settings, argv, name=name, home=home, uid=uid)
422
427
  if platform == "win32":
@@ -425,7 +430,7 @@ def service_definition(
425
430
 
426
431
 
427
432
  def _launch_agent(
428
- paths: OrgPaths,
433
+ paths: RunnerPaths,
429
434
  settings: WorkstationSettings,
430
435
  argv: list[str],
431
436
  *,
@@ -458,19 +463,19 @@ def _launch_agent(
458
463
 
459
464
 
460
465
  def _systemd_user_unit(
461
- paths: OrgPaths,
466
+ paths: RunnerPaths,
462
467
  settings: WorkstationSettings,
463
468
  argv: list[str],
464
469
  *,
465
470
  home: Path,
466
471
  user: str | None,
467
472
  ) -> ServiceDefinition:
468
- unit_name = f"{_LABEL_PREFIX}-{paths.org}.service"
473
+ unit_name = f"{_LABEL_PREFIX}-{paths.name}.service"
469
474
  unit = home / ".config" / "systemd" / "user" / unit_name
470
475
  exec_start = " ".join(_systemd_quote(arg) for arg in argv)
471
476
  content = (
472
477
  "[Unit]\n"
473
- f"Description=Agentic OS Runner for {paths.org}\n"
478
+ f"Description=Agentic OS Runner for {paths.name}\n"
474
479
  "After=network-online.target\n\n"
475
480
  "[Service]\n"
476
481
  f"ExecStart={exec_start}\n"
@@ -504,16 +509,16 @@ def _systemd_quote(value: str) -> str:
504
509
 
505
510
 
506
511
  def _logon_task(
507
- paths: OrgPaths, argv: list[str], *, name: str, user: str | None
512
+ paths: RunnerPaths, argv: list[str], *, name: str, user: str | None
508
513
  ) -> ServiceDefinition:
509
514
  task_xml = paths.state_dir / f"{name}.task.xml"
510
- task_name = f"\\agentic-runner\\{paths.org}"
515
+ task_name = f"\\agentic-runner\\{paths.name}"
511
516
  who = user or os.environ.get("USERNAME", "")
512
517
  arguments = subprocess.list2cmdline(argv[1:])
513
518
  content = f"""<?xml version="1.0" encoding="UTF-16"?>
514
519
  <Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
515
520
  <RegistrationInfo>
516
- <Description>Agentic OS Runner for {escape(paths.org)}</Description>
521
+ <Description>Agentic OS Runner for {escape(paths.name)}</Description>
517
522
  </RegistrationInfo>
518
523
  <Triggers>
519
524
  <LogonTrigger><Enabled>true</Enabled><UserId>{escape(who)}</UserId></LogonTrigger>
@@ -564,7 +569,7 @@ def drive(commands: list[list[str]], *, run: Run = subprocess.run) -> None:
564
569
  # ------------------------------------------------------------------ status
565
570
 
566
571
 
567
- def process_id(paths: OrgPaths) -> int | None:
572
+ def process_id(paths: RunnerPaths) -> int | None:
568
573
  """The running process's pid, if the pidfile names a live one."""
569
574
 
570
575
  try:
@@ -580,7 +585,7 @@ def process_id(paths: OrgPaths) -> int | None:
580
585
  return pid
581
586
 
582
587
 
583
- def heartbeat_age(paths: OrgPaths, *, now: datetime | None = None) -> float | None:
588
+ def heartbeat_age(paths: RunnerPaths, *, now: datetime | None = None) -> float | None:
584
589
  try:
585
590
  stamped = paths.heartbeat_stamp.stat().st_mtime
586
591
  except OSError:
@@ -588,14 +593,14 @@ def heartbeat_age(paths: OrgPaths, *, now: datetime | None = None) -> float | No
588
593
  return max(0.0, (now or datetime.now(UTC)).timestamp() - stamped)
589
594
 
590
595
 
591
- def status_lines(paths: OrgPaths, *, now: datetime | None = None) -> list[str]:
592
- """``status <org>``: the process, its identity and its heartbeat age."""
596
+ def status_lines(paths: RunnerPaths, *, now: datetime | None = None) -> list[str]:
597
+ """``status <name>``: the process, its identity and its heartbeat age."""
593
598
 
594
599
  pid = process_id(paths)
595
600
  state = load_state(paths.state_dir)
596
601
  age = heartbeat_age(paths, now=now)
597
602
  lines = [
598
- f"organisation {paths.org} ({paths.state_dir})",
603
+ f"runner name {paths.name} ({paths.state_dir})",
599
604
  f"process {'running, pid ' + str(pid) if pid else 'not running'}",
600
605
  (
601
606
  f"identity {state.runner_id} in {state.temporal_namespace} on {state.task_queue}"
@@ -634,7 +639,7 @@ def next_step_lines(host_party: str) -> list[str]:
634
639
 
635
640
 
636
641
  async def install(
637
- paths: OrgPaths,
642
+ paths: RunnerPaths,
638
643
  settings: WorkstationSettings,
639
644
  *,
640
645
  registration_token: str,
@@ -645,7 +650,7 @@ async def install(
645
650
  run: Run = subprocess.run,
646
651
  http_client: httpx.AsyncClient | None = None,
647
652
  ) -> list[str]:
648
- """Register this Organisation's process and install its login agent.
653
+ """Register this Runner and install its login agent.
649
654
 
650
655
  Registration happens here, once, with the Runner Registration Token this user minted
651
656
  on /me/runners or the Organisation's Admin issued them (12 A6, QTS-1304) -- pasted at the
@@ -696,18 +701,18 @@ async def install(
696
701
  return lines
697
702
 
698
703
 
699
- def start(paths: OrgPaths, **driver: Any) -> None:
704
+ def start(paths: RunnerPaths, **driver: Any) -> None:
700
705
  _drive_service(paths, "start", **driver)
701
706
 
702
707
 
703
- def stop(paths: OrgPaths, **driver: Any) -> None:
704
- """Stop this Organisation's process; every other Organisation's keeps polling."""
708
+ def stop(paths: RunnerPaths, **driver: Any) -> None:
709
+ """Stop this Runner; every other Runner on this machine keeps polling."""
705
710
 
706
711
  _drive_service(paths, "stop", **driver)
707
712
 
708
713
 
709
714
  def _drive_service(
710
- paths: OrgPaths,
715
+ paths: RunnerPaths,
711
716
  verb: str,
712
717
  *,
713
718
  platform: str = sys.platform,
@@ -719,8 +724,8 @@ def _drive_service(
719
724
  drive(definition.start if verb == "start" else definition.stop, run=run)
720
725
 
721
726
 
722
- def run_process(paths: OrgPaths, *, login_agent: bool) -> int:
723
- """``agentic-runner run --org``: what the login agent executes."""
727
+ def run_process(paths: RunnerPaths, *, login_agent: bool) -> int:
728
+ """``agentic-runner run --name``: what the login agent executes."""
724
729
 
725
730
  settings = WorkstationSettings.load(paths)
726
731
  try:
@@ -730,13 +735,14 @@ def run_process(paths: OrgPaths, *, login_agent: bool) -> int:
730
735
  return 1
731
736
  for name, value in run_environment(paths, settings).items():
732
737
  os.environ[name] = value
733
- store = open_workstation_store(paths.org, fallback=paths.credentials)
738
+ store = open_workstation_store(paths.name, fallback=paths.credentials)
734
739
  attestation = collect_attestation(
735
740
  channel=settings.install_channel,
736
741
  session=SessionKind.LOGIN_AGENT if login_agent else SessionKind.INTERACTIVE,
737
742
  store=store.kind,
738
743
  path=settings.path,
739
744
  )
740
- # A workstation's hostname can name its person, so it is never reported (rev 3).
741
- install = RunnerInstall(target=InstallTarget.WORKSTATION)
745
+ # A workstation's hostname can name its person, so it is never reported (rev 3); the
746
+ # name it was installed as is the person's choice, and the console lists it (QTS-1773).
747
+ install = RunnerInstall(target=InstallTarget.WORKSTATION, name=paths.name)
742
748
  return asyncio.run(service.run(host_store=store, attestation=attestation, install=install))
File without changes