ms-tau-sdk 2.0.6.dev40__tar.gz → 2.0.7.dev42__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 (86) hide show
  1. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/CHANGELOG.md +39 -0
  2. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/PKG-INFO +12 -10
  3. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/README.md +11 -9
  4. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/pyproject.toml +1 -1
  5. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/__init__.py +2 -2
  6. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/agent_skills/tau_a2a_runtime_adapter/SKILL.md +7 -8
  7. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/agent_skills/tau_project_customization/SKILL.md +44 -33
  8. ms_tau_sdk-2.0.7.dev42/src/ms_tau_sdk/agent_skills/tau_security_and_access/SKILL.md +244 -0
  9. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/api/a2a.py +20 -48
  10. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/backend/client.py +25 -19
  11. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/backend/local.py +30 -10
  12. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/runtime/manager.py +37 -53
  13. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/runtime/requester.py +220 -120
  14. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/runtime/task_context.py +5 -4
  15. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/tools/mainsequence_mcp.py +34 -63
  16. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/tools/mcp_applications.py +15 -23
  17. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/tools/mcp_connection.py +3 -10
  18. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/.gitignore +0 -0
  19. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/packages/tau-board/src/ms_tau_board/__init__.py +0 -0
  20. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/packages/tau-board/src/ms_tau_board/app.py +0 -0
  21. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/packages/tau-board/src/ms_tau_board/cli.py +0 -0
  22. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/packages/tau-board/src/ms_tau_board/config.py +0 -0
  23. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/packages/tau-board/src/ms_tau_board/env_file.py +0 -0
  24. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/packages/tau-board/src/ms_tau_board/logs.py +0 -0
  25. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/packages/tau-board/src/ms_tau_board/proxy.py +0 -0
  26. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/packages/tau-board/src/ms_tau_board/state.py +0 -0
  27. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/packages/tau-board/src/ms_tau_board/static/BULMA-LICENSE.txt +0 -0
  28. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/packages/tau-board/src/ms_tau_board/static/app.js +0 -0
  29. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/packages/tau-board/src/ms_tau_board/static/board.css +0 -0
  30. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/packages/tau-board/src/ms_tau_board/static/bulma.min.css +0 -0
  31. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/packages/tau-board/src/ms_tau_board/static/index.html +0 -0
  32. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/agent_skills/tau_local_development/SKILL.md +0 -0
  33. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/agent_skills/tau_repository_integration/SKILL.md +0 -0
  34. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/api/__init__.py +0 -0
  35. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/api/chat.py +0 -0
  36. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/api/conversations.py +0 -0
  37. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/api/dependencies.py +0 -0
  38. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/api/health.py +0 -0
  39. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/api/inspection.py +0 -0
  40. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/api/local_chat.py +0 -0
  41. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/api/models.py +0 -0
  42. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/api/request_identity.py +0 -0
  43. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/api/sessions.py +0 -0
  44. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/app.py +0 -0
  45. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/application.py +0 -0
  46. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/backend/__init__.py +0 -0
  47. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/backend/assertions.py +0 -0
  48. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/backend/auth.py +0 -0
  49. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/backend/mcp.py +0 -0
  50. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/backend/models.py +0 -0
  51. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/backend/routes.py +0 -0
  52. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/cli.py +0 -0
  53. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/errors.py +0 -0
  54. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/logging.py +0 -0
  55. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/protocols/__init__.py +0 -0
  56. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/protocols/a2a_failure.py +0 -0
  57. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/protocols/a2a_message.py +0 -0
  58. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/protocols/a2a_roles.py +0 -0
  59. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/protocols/assistant_ui.py +0 -0
  60. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/protocols/chat_history.py +0 -0
  61. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/protocols/strict_json.py +0 -0
  62. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/providers/__init__.py +0 -0
  63. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/providers/definitions.py +0 -0
  64. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/providers/factory.py +0 -0
  65. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/providers/tau_compat.py +0 -0
  66. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/resources/SYSTEM.md +0 -0
  67. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/resources/__init__.py +0 -0
  68. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/resources/loader.py +0 -0
  69. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/resources/prompts/review-code-repository.md +0 -0
  70. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/runtime/__init__.py +0 -0
  71. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/runtime/deployment_health.py +0 -0
  72. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/runtime/events.py +0 -0
  73. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/runtime/extensions.py +0 -0
  74. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/runtime/failures.py +0 -0
  75. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/runtime/live_turns.py +0 -0
  76. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/runtime/observability.py +0 -0
  77. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/runtime/provenance.py +0 -0
  78. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/runtime/session.py +0 -0
  79. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/runtime/snapshots.py +0 -0
  80. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/sessions/__init__.py +0 -0
  81. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/sessions/storage.py +0 -0
  82. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/settings.py +0 -0
  83. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/skills.py +0 -0
  84. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/tools/__init__.py +0 -0
  85. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/tools/skill_read.py +0 -0
  86. {ms_tau_sdk-2.0.6.dev40 → ms_tau_sdk-2.0.7.dev42}/src/ms_tau_sdk/tools/task_control.py +0 -0
@@ -2,6 +2,45 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ - **Breaking: one delegation envelope on every call made for the work
6
+ ([#78](https://github.com/mainsequence-sdk/ms-tau-sdk/issues/78), ADR 0021 amendment).** This
7
+ release works only with the matching platform change, deployed in the same cutover; there is no
8
+ deprecation period, and earlier releases, including 2.0.6, stop acting for people once that
9
+ platform is deployed.
10
+ - Every hosted Main Sequence MCP call names the turn's session, and carries the person's
11
+ delegation (`mainsequence.ai/delegation/v1`) while the turn serves a person. The platform's
12
+ per-tool labels (`mainsequence.ai/requires-requester/v1`,
13
+ `mainsequence.ai/requires-caller-session-proof/v1`) are no longer read, and a turn that serves
14
+ nobody keeps its MCP tools: its calls are the Agent's own.
15
+ - Declared application tools run in every turn, with a token for the person the turn serves or
16
+ the Agent's own token when it serves nobody. A refused delegated call is reported and never
17
+ retried as the Agent.
18
+ - The person a turn serves comes only from the platform's answer to the turn start, whoever
19
+ called; dispatch, delivery and Task answers are no longer read for it. Delegated work serves
20
+ the person the platform records for it.
21
+ - `platform_client()` replaces `requester_client()`, with no alias. By default a call carries the
22
+ delegation while the turn serves a person; `delegation="none"` never carries it and
23
+ `delegation="required"` refuses the call before sending when the turn serves nobody. Outside a
24
+ turn no call carries a delegation, and in local mode calls use the signed-in person's own
25
+ credential.
26
+ - Delegated calls use the person's ordinary permissions, including administrative ones; the
27
+ statement people are shown changes accordingly.
28
+ - The SDK no longer hides the withdrawn private Secret entry operations, and the local health
29
+ field `mcp_session_proof_limited_tool_count` is removed.
30
+
31
+ - A new packaged skill, `tau_security_and_access`, teaches building project tools that act for the
32
+ person a turn serves: which delegation each tool should use, a worked example of tools that use
33
+ a person's own Secret without exposing it to the model, and how sharing decides what a delegated
34
+ call can reach. `ms-tau skills sync` now installs five skills.
35
+
36
+ - Documentation now distinguishes requester-bound reads and supported writes from workload grants,
37
+ states the write risk and platform rollout requirements, and includes conversation/Task
38
+ permissions and denial recovery. The Security and access guide keeps its `security-model.md`
39
+ path. Provider selection settings and troubleshooting, the public readiness-hook reference, and
40
+ the exported API compatibility list are complete. This changes documentation only.
41
+
42
+ ## 2.0.6 — 2026-10-07
43
+
5
44
  - The documentation no longer describes the platform's internal implementation. It no longer names
6
45
  the backend framework, its repositories, ADRs, classes or commits, and calls the backend "the
7
46
  platform". The archived Astro documents (`docs/history/astro`) and the ADR 56 migration workspace
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: ms-tau-sdk
3
- Version: 2.0.6.dev40
3
+ Version: 2.0.7.dev42
4
4
  Summary: Workspace-bound Tau application primitives for Main Sequence projects
5
5
  Project-URL: Changelog, https://github.com/mainsequence-sdk/ms-tau-sdk/blob/development/CHANGELOG.md
6
6
  Project-URL: Documentation, https://github.com/mainsequence-sdk/ms-tau-sdk/tree/development/docs
@@ -133,10 +133,11 @@ only an application that declares it, so serve the application `create_app()` re
133
133
  hosting, requests are handled as before. See
134
134
  [request identity](docs/reference/runtime-contract.md#request-identity).
135
135
 
136
- An Agent that an Organization admin enabled for it can read with the access of the person whose
137
- request a turn is serving. Project tools read that person with `current_requester()` and call the
138
- platform or another platform application for them with `requester_client()`; neither exposes a
139
- proof or a token. See the [public API](docs/reference/public-api.md#current_requester-and-requester_client).
136
+ An Agent that an Organization admin enabled for it can act with the ordinary permissions of the
137
+ person whose request a turn is serving. Project tools read that person with `current_requester()`
138
+ and call the platform or another platform application with `platform_client()`, which carries the
139
+ person's delegation by default while the turn serves one; neither exposes a proof or a token. See
140
+ the [public API](docs/reference/public-api.md#current_requester-and-platform_client).
140
141
 
141
142
  Job-hosted batch execution is an [accepted design](docs/adrs/0015-job-hosted-batch-execution.md)
142
143
  with implementation pending. It will run this SDK's configured Tau composition for one assignment
@@ -287,13 +288,14 @@ are not bundled into the SDK. Main Sequence transport and protocol behavior rema
287
288
  - explicit, version-matched development skills for repository integration, local debugging,
288
289
  project customization, and TAU's A2A host adapter
289
290
 
290
- ## Security model
291
+ ## Security and access guide
291
292
 
292
- A hosted Agent runs as its own workload, with no access until it is granted, and never reads or
293
- writes Secret values. An Organization admin can let it read with the access of the person it is
294
- serving, read-only and for at most 24 hours. Everything its tools read reaches the model, and its
293
+ A hosted Agent runs as its own workload, with no access until it is granted. An Organization admin
294
+ can let it act with the ordinary permissions of the person it serves, including administrative
295
+ ones, only during that work and for at most 24 hours. Prompt injection can cause unintended actions within those rights;
296
+ completed changes can outlast that access. Everything its tools read reaches the model, and its
295
297
  tools and extensions run with its credentials. The
296
- [agent security model](docs/reference/security-model.md) explains what people who build and use
298
+ [Security and access guide](docs/reference/security-model.md) explains what people who build and use
297
299
  Agents need to know.
298
300
 
299
301
  ## Deployment boundary
@@ -100,10 +100,11 @@ only an application that declares it, so serve the application `create_app()` re
100
100
  hosting, requests are handled as before. See
101
101
  [request identity](docs/reference/runtime-contract.md#request-identity).
102
102
 
103
- An Agent that an Organization admin enabled for it can read with the access of the person whose
104
- request a turn is serving. Project tools read that person with `current_requester()` and call the
105
- platform or another platform application for them with `requester_client()`; neither exposes a
106
- proof or a token. See the [public API](docs/reference/public-api.md#current_requester-and-requester_client).
103
+ An Agent that an Organization admin enabled for it can act with the ordinary permissions of the
104
+ person whose request a turn is serving. Project tools read that person with `current_requester()`
105
+ and call the platform or another platform application with `platform_client()`, which carries the
106
+ person's delegation by default while the turn serves one; neither exposes a proof or a token. See
107
+ the [public API](docs/reference/public-api.md#current_requester-and-platform_client).
107
108
 
108
109
  Job-hosted batch execution is an [accepted design](docs/adrs/0015-job-hosted-batch-execution.md)
109
110
  with implementation pending. It will run this SDK's configured Tau composition for one assignment
@@ -254,13 +255,14 @@ are not bundled into the SDK. Main Sequence transport and protocol behavior rema
254
255
  - explicit, version-matched development skills for repository integration, local debugging,
255
256
  project customization, and TAU's A2A host adapter
256
257
 
257
- ## Security model
258
+ ## Security and access guide
258
259
 
259
- A hosted Agent runs as its own workload, with no access until it is granted, and never reads or
260
- writes Secret values. An Organization admin can let it read with the access of the person it is
261
- serving, read-only and for at most 24 hours. Everything its tools read reaches the model, and its
260
+ A hosted Agent runs as its own workload, with no access until it is granted. An Organization admin
261
+ can let it act with the ordinary permissions of the person it serves, including administrative
262
+ ones, only during that work and for at most 24 hours. Prompt injection can cause unintended actions within those rights;
263
+ completed changes can outlast that access. Everything its tools read reaches the model, and its
262
264
  tools and extensions run with its credentials. The
263
- [agent security model](docs/reference/security-model.md) explains what people who build and use
265
+ [Security and access guide](docs/reference/security-model.md) explains what people who build and use
264
266
  Agents need to know.
265
267
 
266
268
  ## Deployment boundary
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "ms-tau-sdk"
7
- version = "2.0.6.dev40"
7
+ version = "2.0.7.dev42"
8
8
  description = "Workspace-bound Tau application primitives for Main Sequence projects"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.13"
@@ -9,7 +9,7 @@ from .runtime.deployment_health import (
9
9
  RUNTIME_HEALTH_ABI_VERSION,
10
10
  register_deployment_readiness_hook,
11
11
  )
12
- from .runtime.requester import current_requester, requester_client
12
+ from .runtime.requester import current_requester, platform_client
13
13
  from .settings import TauSDKSettings
14
14
 
15
15
  __all__ = [
@@ -18,6 +18,6 @@ __all__ = [
18
18
  "__version__",
19
19
  "create_app",
20
20
  "current_requester",
21
+ "platform_client",
21
22
  "register_deployment_readiness_hook",
22
- "requester_client",
23
23
  ]
@@ -23,19 +23,18 @@ The SDK owns:
23
23
 
24
24
  - projecting the authenticated Main Sequence MCP catalog into a TAU session;
25
25
  - preserving each tool's canonical name and metadata through host normalization;
26
- - privately attaching active caller-session proof when a tool advertises
27
- `mainsequence.ai/requires-caller-session-proof/v1: true`;
28
- - attaching the same proof when a tool advertises `mainsequence.ai/requires-requester/v1: true`,
29
- which the platform runs for the turn's requester, and refusing that tool before sending it in a
30
- hosted turn that serves nobody;
26
+ - privately attaching, to every hosted Main Sequence MCP call, the turn's caller-session proof under
27
+ `mainsequence.ai/caller-session-proof/v1`, and, while the turn serves a person, the same proof as
28
+ that person's delegation under `mainsequence.ai/delegation/v1`. No tool metadata decides it;
31
29
  - verifying the platform's signed caller or platform assertion on every inbound request of a
32
30
  hosted runtime, and admitting a request to a session or its Tasks only for the session's owner,
33
31
  an Organization admin, or the workload User of the Agent that delegated to that child session,
34
32
  which the platform's own records establish, never the `X-Caller-*` headers;
35
33
  - presenting the verified caller assertion of the request that starts a chat or A2A Message turn
36
- only when it marks that turn active, so that the platform can record the turn's requester, and
37
- giving extension tools that requester and requester-bound calls through `current_requester()`
38
- and `requester_client()` without exposing the assertion, the lease proof, or any token;
34
+ only when it marks that turn active, so that the platform can record the turn's requester;
35
+ taking the person the turn serves only from the platform's answer to the turn start; and giving
36
+ extension tools that person and calls for the work through `current_requester()` and
37
+ `platform_client()` without exposing the assertion, the lease proof, or any token;
39
38
  - translating inbound A2A requests into the shared TAU runtime; and
40
39
  - translating runtime events and results into validated A2A responses.
41
40
 
@@ -97,10 +97,11 @@ tools do not grant new platform permissions merely because they run inside TAU.
97
97
 
98
98
  ## Acting for the person a turn serves
99
99
 
100
- An Agent that an Organization admin enabled for it can read platform data, and ask other platform
101
- applications, with the access of the person whose request a turn is serving: the requester. The
102
- platform keeps that authority and finds the person in its own records; the runtime only proves
103
- which of its sessions it is working on. Extension tools use two SDK functions and nothing else:
100
+ An Agent that an Organization admin enabled for it can call the platform and other platform
101
+ applications with the ordinary permissions of the person whose request a turn is serving: the
102
+ requester. The platform keeps that authority and finds the person in its own records; the runtime
103
+ only proves which of its sessions it is working on. Extension tools use two SDK functions and
104
+ nothing else:
104
105
 
105
106
  ```python
106
107
  import json
@@ -108,64 +109,74 @@ import json
108
109
  from tau_agent.messages import TextContent
109
110
  from tau_agent.tools import AgentToolResult
110
111
 
111
- from ms_tau_sdk import current_requester, requester_client
112
+ from ms_tau_sdk import platform_client
112
113
 
113
114
  ANALYST_DATA_RELEASE_UID = "..." # the release of the application to ask
114
115
 
115
116
 
116
117
  async def revenue_by_region(tool_call_id, arguments, signal=None, on_update=None):
117
- if current_requester() is None:
118
- return AgentToolResult(content=[TextContent(text="Ask me from your own conversation.")])
118
+ # This tool answers each person with their own data, so it needs a person.
119
119
  try:
120
- answer = await requester_client().call_release(
120
+ answer = await platform_client(delegation="required").call_release(
121
121
  ANALYST_DATA_RELEASE_UID,
122
122
  "POST",
123
123
  "/query",
124
124
  json={"question": "revenue by region"},
125
125
  )
126
126
  except PermissionError:
127
- return AgentToolResult(content=[TextContent(text="Your access for this request ended.")])
127
+ return AgentToolResult(content=[TextContent(text="Ask me from your own conversation.")])
128
128
  return AgentToolResult(content=[TextContent(text=json.dumps(answer.json()["rows"]))])
129
129
  ```
130
130
 
131
- - `current_requester()` returns the turn's verified requester, with `uid` and `team_uids`, or
132
- `None`. It is `None` for Agent callers, the platform's own calls other than a caller delivery
133
- (which resumes delegated work for the person who asked), local mode, and code outside a turn.
134
- Only it names the requester:
135
- never take a person's UID from tool arguments, the prompt, history, or a header.
136
- - `requester_client()` returns a client bound to the turn. `await client.request("GET",
137
- "/api/v1/...")` reads a platform API path for the requester. `await client.call_release(
138
- release_uid, method, path, ...)` asks another platform application, which answers as the
139
- requester. Both return an `httpx.Response`.
140
- - Without a requester, `requester_client()` raises a `PermissionError`. So does a call that the
141
- platform refuses because the requester's access ended (`code` `requester_binding_invalid` or
142
- `runtime_lease_*`): the turn is over, the access was removed, more than 24 hours passed, or the
143
- Agent is not enabled. Catch it, say in plain words that the request cannot be served, and never
144
- fall back to the Agent's own access.
131
+ - `current_requester()` returns the person the turn serves, with `uid` and `team_uids`, or
132
+ `None`. The platform names that person when the turn starts, whoever called; it is `None` when
133
+ the platform names nobody, in local mode, and in code outside a turn. Only it names the
134
+ requester: never take a person's UID from tool arguments, the prompt, history, or a header.
135
+ - `platform_client()` returns a client. `await client.request("GET", "/api/v1/...")` calls a
136
+ platform API path, and `await client.call_release(release_uid, method, path, ...)` calls another
137
+ platform application. Both return an `httpx.Response`.
138
+ - By default (`delegation="auto"`) a call carries the person's delegation while the turn serves a
139
+ person, and is the Agent's own otherwise; the operation or application decides what it may do.
140
+ `delegation="none"` never carries it. `delegation="required"` raises a `PermissionError` before
141
+ sending when the turn serves nobody; use it in a tool that only makes sense for a person.
142
+ - A call the platform refuses because the person's access ended (`code`
143
+ `requester_binding_invalid` or `runtime_lease_*`) raises a `PermissionError`: the turn is over,
144
+ the access was removed, more than 24 hours passed, or the Agent is not enabled. Catch it, say in
145
+ plain words that the request cannot be served, and never retry it as the Agent.
145
146
 
146
147
  Rules for tools that act for the requester:
147
148
 
148
149
  - Never handle proofs or tokens. The SDK attaches the session, the lease proof, and the
149
150
  credentials itself. A tool never reads, logs, stores, or forwards them, passes a path rather than
150
151
  a URL, and never sets `Authorization` or an `X-MainSequence-*` header.
151
- - Requester-bound calls are read-only. The platform refuses writes, sharing, and Secret values;
152
- do not build tools that try them.
152
+ - A delegated call uses the person's ordinary permissions, including administrative ones; any other
153
+ call uses the Agent's own. Each operation decides what it needs. Never infer write permission
154
+ from view access.
155
+ - This needs the platform's matching change, deployed in the same cutover; check the deployed
156
+ platform and the installed SDK before depending on it.
153
157
  - Return to the model only business results, such as rows, numbers, and names. Never return the
154
158
  response object, its headers, a token, a proof, or a raw error body.
155
- - Keep nothing for another turn or another person. The binding ends with the turn, and a task the
156
- tool leaves running has no access afterwards.
159
+ - Keep nothing for another turn or another person. The delegation ends with the turn, and a task
160
+ the tool leaves running acts only as the Agent afterwards.
157
161
  - What a tool reads for a person belongs to that person's conversation. Do not write it to shared
158
162
  stores, other Agents, or external systems.
159
163
 
160
164
  People who use such an Agent are told:
161
165
 
162
- > **This Agent works with your identity, securely.** It reads only what you can already read, only
163
- > to answer your own requests, and for at most 24 hours after you ask. It cannot act as anyone else,
164
- > cannot change, share or delete anything, never sees your secret values, and stops the moment your
165
- > access ends. Your Organization's administrator approved it to work this way.
166
+ > **This Agent works with your identity.** It can read, create, change, run,
167
+ > share or delete only what your permissions allow through supported operations,
168
+ > only while serving your request, and for at most 24 hours after you ask. It
169
+ > uses your ordinary permissions, including administrative permissions, and
170
+ > access is checked on every call. Your Organization's administrator approved it
171
+ > to work this way.
172
+
173
+ The statement describes delegated calls. The Agent's own grants and trusted extension code remain
174
+ separate authority. Prompt injection can cause unintended changes, sharing, or deletion within the
175
+ person's permissions, and completed writes can outlast the delegation. Only Organization admins
176
+ enable this authority.
166
177
 
167
- The limit is plain: while it works on your request, the Agent's code can read what you can read,
168
- which is why only administrators decide which Agents may work this way.
178
+ For a complete example, a tool that uses a person's Secret without exposing it, and how sharing
179
+ decides what a delegated call can reach, use `tau_security_and_access`.
169
180
 
170
181
  ## Validation
171
182
 
@@ -0,0 +1,244 @@
1
+ ---
2
+ name: tau-security-and-access
3
+ description: Build and review project tools that call the platform or other applications for the person a turn serves, including tools that use a person's Secret without exposing it, and explain how delegation and sharing decide what those tools can reach.
4
+ ---
5
+
6
+ # TAU Security and Access
7
+
8
+ Use this skill when a project tool under `.tau/extensions/` calls the platform or another
9
+ platform application, uses a Secret, or must answer each person with their own data. Extension
10
+ mechanics are in `tau_project_customization`. The full model, with the administrator setup, is in
11
+ the SDK's Security and access guide (`docs/reference/security-model.md`). Sharing itself is in
12
+ `.agents/skills/mainsequence/platform_operations/access_control_and_sharing/SKILL.md`.
13
+
14
+ ## Who a call acts as
15
+
16
+ Every call a tool makes through `platform_client()` follows one rule:
17
+
18
+ | The call carries | Permissions used |
19
+ | --- | --- |
20
+ | No delegation | The caller's own: the Agent's workload grants, or in local mode your own login. |
21
+ | A valid delegation | The person the turn serves, with their ordinary permissions, including administrative ones. |
22
+ | A delegation that ended or is invalid | None. The call is refused with a `PermissionError` and is never retried as the Agent. |
23
+
24
+ - The platform names the person when the turn starts, and `current_requester()` returns them. It
25
+ returns `None` when the Agent is not enabled to act for people (only an Organization admin can
26
+ enable it, with `acts_for_requester`), for work no person asked for, in local mode and outside a
27
+ turn.
28
+ - The operation or application that receives the call decides what it may do. No list says which
29
+ operations accept a delegation. Read access never implies edit, run, share or delete.
30
+ - The call stays the Agent's call, made for the person. It is not impersonation: the platform
31
+ checks it on every call, only while the turn or Task serving the person runs, for at most 24
32
+ hours after their request, and only in the Agent's Environment.
33
+
34
+ ## Choose the delegation for each tool
35
+
36
+ | The tool | `delegation` |
37
+ | --- | --- |
38
+ | Answers each person with their own data, or uses their credentials | `"required"` |
39
+ | Works for anyone, for the person when the turn serves one | `"auto"` (the default) |
40
+ | Uses only the Agent's own resources, the same for everyone | `"none"` |
41
+
42
+ With `"required"`, a turn that serves nobody raises a `PermissionError` before anything is sent.
43
+ With `"auto"`, the same tool reaches different things for different people, and the Agent's own
44
+ grants when nobody is served: make sure both are what you intend. Local turns serve nobody, so a
45
+ `"required"` tool refuses in local mode; test it with fakes (see [Testing](#testing)).
46
+
47
+ ## Example: a tool that uses a person's own Secret
48
+
49
+ A person stores an API key for an outside data provider, and the Agent uses it for them without
50
+ ever seeing it:
51
+
52
+ 1. The person creates the Secret themselves. The Agent never asks for the value or accepts it.
53
+ 2. The tool that calls the provider reads the Secret as the person, inside that same call.
54
+ 3. The tool uses the value and returns only the result.
55
+
56
+ ```python
57
+ """Quotes from an outside provider, with each person's own API key."""
58
+
59
+ import json
60
+
61
+ import httpx
62
+ from tau_agent.messages import TextContent
63
+ from tau_agent.tools import AgentTool, AgentToolResult
64
+
65
+ from ms_tau_sdk import current_requester, platform_client
66
+
67
+ PROVIDER_URL = "https://quotes.example.test/v1/latest"
68
+
69
+
70
+ def _text(message):
71
+ return AgentToolResult(content=[TextContent(text=message)])
72
+
73
+
74
+ def _secret_name():
75
+ # The name comes from the person the platform named, never from the model.
76
+ person = current_requester()
77
+ return None if person is None else f"QUOTES_API_KEY__{person.uid}"
78
+
79
+
80
+ async def _secret_uid(client, name):
81
+ # Listing returns names and UIDs, never values. Names are unique in the Agent's Environment.
82
+ answer = await client.request("GET", "/api/v1/secrets/", params={"name": name})
83
+ if answer.status_code != 200:
84
+ return None
85
+ found = answer.json()["results"]
86
+ return found[0]["uid"] if found else None
87
+
88
+
89
+ async def connect_quotes(tool_call_id, arguments, signal=None, on_update=None):
90
+ name = _secret_name()
91
+ if name is None:
92
+ return _text("I can set up your key only while answering your own request.")
93
+ try:
94
+ uid = await _secret_uid(platform_client(delegation="required"), name)
95
+ except PermissionError:
96
+ return _text("Your access for this request ended. Please ask again.")
97
+ if uid is not None:
98
+ return _text(f"Your key is stored as the Secret {name}.")
99
+ return _text(
100
+ f"Create a Secret named {name} with your API key, in the Environment this Agent runs in: "
101
+ f"on the Secrets page in Command Center, or with `mainsequence secrets create {name}`, "
102
+ "which asks for the value without showing it. Never paste the key into this chat."
103
+ )
104
+
105
+
106
+ async def latest_quote(tool_call_id, arguments, signal=None, on_update=None):
107
+ name = _secret_name()
108
+ if name is None:
109
+ return _text("I can use your key only while answering your own request.")
110
+ client = platform_client(delegation="required")
111
+ try:
112
+ uid = await _secret_uid(client, name)
113
+ if uid is None:
114
+ return _text(f"First create the Secret {name}. Ask me how.")
115
+ secret = await client.request("GET", f"/api/v1/secrets/{uid}/")
116
+ except PermissionError:
117
+ return _text("Your access for this request ended. Please ask again.")
118
+ if secret.status_code != 200:
119
+ return _text("I could not read your key.")
120
+ try:
121
+ async with httpx.AsyncClient(timeout=10.0) as http:
122
+ quote = await http.get(
123
+ PROVIDER_URL,
124
+ params={"symbol": arguments["symbol"]},
125
+ headers={"Authorization": f"Bearer {secret.json()['value']}"},
126
+ )
127
+ except httpx.HTTPError:
128
+ # The error can carry the request with its headers: never show it.
129
+ return _text("The quotes provider did not answer.")
130
+ if quote.status_code != 200:
131
+ return _text(f"The quotes provider answered {quote.status_code}.")
132
+ data = quote.json()
133
+ return _text(json.dumps({"symbol": data["symbol"], "price": data["price"]}))
134
+
135
+
136
+ def setup(tau):
137
+ tau.register_tool(
138
+ AgentTool(
139
+ name="connect_quotes",
140
+ label="Connect Quotes",
141
+ description="Check or explain how to store your quotes API key as your own Secret.",
142
+ parameters={"type": "object", "properties": {}, "additionalProperties": False},
143
+ execute_fn=connect_quotes,
144
+ )
145
+ )
146
+ tau.register_tool(
147
+ AgentTool(
148
+ name="latest_quote",
149
+ label="Latest Quote",
150
+ description="Get the latest quote for a symbol with your own quotes API key.",
151
+ parameters={
152
+ "type": "object",
153
+ "properties": {"symbol": {"type": "string"}},
154
+ "required": ["symbol"],
155
+ "additionalProperties": False,
156
+ },
157
+ execute_fn=latest_quote,
158
+ )
159
+ )
160
+ ```
161
+
162
+ What makes it safe:
163
+
164
+ - No tool takes a Secret value or a Secret name from the model. The name is built from
165
+ `current_requester().uid`, so prompt injection cannot point the tool at another Secret.
166
+ - `delegation="required"` reads the Secret as the person. The platform returns it only if the
167
+ person can view it; the name is a lookup key, not the protection.
168
+ - The value exists only inside one call. It never goes into the result, `details`, a log, an
169
+ exception message, a file or a cache for the next turn. It travels in a header, never in a URL,
170
+ because URLs reach logs. Errors from the outside call are caught, and the provider's raw body is
171
+ never returned.
172
+ - There is no tool that returns a Secret value, and no tool that calls any platform path the model
173
+ chooses. With the delegation, such a tool would let the model read every Secret the person can.
174
+ - The Agent's own workload holds no grant on these Secrets, so a call without the person reaches
175
+ none of them.
176
+
177
+ ## Sharing decides what a delegated call can reach
178
+
179
+ A delegated read returns anything the person can view in the Agent's Environment: what they
180
+ created and what others shared with them, directly or through a team. This holds for Secrets and
181
+ every other object. The platform enforces sharing; which of those objects a tool uses is part of
182
+ the tool's design. For Secrets, the naming convention states that design:
183
+
184
+ - **A personal credential:** a name tied to the person, such as `QUOTES_API_KEY__<person uid>`.
185
+ The person decides whether to share it.
186
+ - **A team credential:** a name the team agrees on, shared with the team for view. The tool reads
187
+ it for any member.
188
+ - **Someone else's Secret shared with the person:** valid whenever the tool is meant to use it.
189
+
190
+ Whoever can edit a Secret decides its value, so the tool uses whatever value they set. Granting or
191
+ accepting edit on a Secret means trusting that person with what the tool does with it. That is a
192
+ decision people make through sharing, not one the platform makes for them.
193
+
194
+ How sharing works:
195
+
196
+ - The creator of a Secret can always view and edit it, and cannot be removed from it. People who
197
+ can edit a Secret can share it, for view or for edit, with people and teams.
198
+ - Most people can share only within the teams they belong to; Organization admins can share
199
+ across their Organization.
200
+ - `GET /api/v1/secrets/<uid>/can-view/` and `can-edit/` list the people and teams with access. A
201
+ tool can use them when its design needs to, for example to refuse a team key where it expects a
202
+ personal one. That is a choice of the tool, not a platform rule.
203
+
204
+ ## What never reaches the model
205
+
206
+ Tool results, their `details`, and errors can reach the model provider and the session history.
207
+ Never return a Secret value, a token, a proof, an assertion, a response object, its headers or a
208
+ raw error body. Return business results: rows, numbers, names, and plain messages. The SDK already
209
+ keeps its own credentials out of that path and never lets a tool set `Authorization` or an
210
+ `X-MainSequence-*` header.
211
+
212
+ ## Limits
213
+
214
+ - This works in the Agent's own project tools. An application that receives a delegated call
215
+ learns the person with `User.get_requester()`, but it cannot call the platform as that person.
216
+ - The delegation ends with the turn. A task the tool leaves running acts as the Agent afterwards,
217
+ and nothing read for one person may be kept for another turn or another person.
218
+ - When the person's access ends (the turn is over, the access was removed, 24 hours passed, or
219
+ the Agent is not enabled), calls raise a `PermissionError` whose `code` is
220
+ `requester_binding_invalid` or starts with `runtime_lease_`. Say in plain words that the request
221
+ cannot be served, and never retry it as the Agent.
222
+ - Every other answer, such as `403` or `404` for an object the person cannot see, is returned as
223
+ it is: check the status before using the body.
224
+
225
+ ## Testing
226
+
227
+ Patch the extension module's `current_requester` and `platform_client` with fakes, and test:
228
+
229
+ - with a person and the Secret: the result holds only business fields, and the value appears in no
230
+ result text, `details`, log record or exception;
231
+ - with a person and no Secret: the tool explains how to create it and sends no provider call;
232
+ - with nobody: the tool refuses and sends nothing;
233
+ - a `PermissionError` from the client: a plain message, and no second call;
234
+ - a failing or erroring provider: a plain message without the provider's body or the request.
235
+
236
+ ## Review checklist
237
+
238
+ - Each tool has a deliberate `delegation`: `"required"` for a person's own data or credentials.
239
+ - No person's UID, Secret name or Secret value comes from tool arguments, the prompt or history.
240
+ - No tool returns a credential or calls a platform path the model chooses.
241
+ - Secret values stay inside one call, in headers, never in results, logs, errors, URLs or caches.
242
+ - The naming convention says whose Secrets the tool uses, and the people sharing them know it.
243
+ - A refused delegated call is reported, never retried as the Agent.
244
+ - The Agent's workload holds no grants it does not need, and none on people's Secrets.