Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
7ac3398
apply dependabot insights
alain-sv May 13, 2026
22d50aa
minor
alain-sv May 13, 2026
2a89660
chore(ci): SHA-pin actions/checkout and actions/setup-python (#43)
alain-sv May 13, 2026
297d98e
docs(changelog): add unreleased dependency security refresh entry (#44)
alain-sv May 13, 2026
1c41f54
chore(ci): add uv cache-suffix per Python version + update AGENTS.md …
alain-sv May 13, 2026
00aad5e
Merge branch 'main' into develop
alain-sv May 13, 2026
1f5c176
supervaizer-v2-mvp-contracts (#47)
alain-sv May 17, 2026
d7c98b9
Minor
alain-sv May 17, 2026
b192229
Merge branch 'main' into develop
alain-sv May 17, 2026
789b0c6
chore: update changelog for Supervaizer v2 enhancements and API key v…
alain-sv May 17, 2026
da4b00d
Merge branch 'main' into develop
alain-sv May 17, 2026
c977b6e
workspace-agent-grants (#50)
alain-sv May 19, 2026
a12b628
minor
alain-sv May 19, 2026
a761421
Merge branch 'main' into develop
alain-sv May 20, 2026
1f20b22
feat(logging): implement structured logging for Cloud Logging compati…
alain-sv May 20, 2026
746a04f
Merge branch 'main' into develop
alain-sv May 24, 2026
75a3a0d
Minor
alain-sv May 24, 2026
612001f
Merge branch 'main' into develop
alain-sv May 26, 2026
3324db5
codex/supervaizer-lifespan-cleanup (#54)
alain-sv May 26, 2026
e7834a2
codex/refactor-server-modules (#55)
alain-sv May 26, 2026
4fed877
minor
alain-sv May 26, 2026
afaf602
codex/agent-interviewer-workspace-jobs-refresh (#56)
alain-sv May 26, 2026
ceede13
Refactor pre-commit configuration and enhance agent validation
alain-sv May 26, 2026
62f299d
Merge branch 'main' into develop
alain-sv May 27, 2026
ea6ce6c
chore(deps): bump uv from 0.11.14 to 0.11.15 (#58)
dependabot[bot] May 30, 2026
770a668
chore(deps): bump starlette from 0.50.0 to 1.0.1 (#60)
dependabot[bot] Jun 6, 2026
15e586e
chore(deps): bump trufflesecurity/trufflehog from 3.95.3 to 3.95.5 (#61)
dependabot[bot] Jun 9, 2026
4d5703a
feat(.agents): add skill symlinks from runwaize skills cookbook
alain-sv Jun 17, 2026
f197480
chore(deps): bump astral-sh/setup-uv from 8.1.0 to 8.2.0 (#62)
dependabot[bot] Jun 20, 2026
b50b3e9
chore(deps): bump actions/checkout from 6.0.2 to 6.0.3 (#63)
dependabot[bot] Jun 20, 2026
4461b3e
chore(deps): bump starlette from 1.0.1 to 1.3.1 (#66)
dependabot[bot] Jun 20, 2026
287b498
chore(deps): bump cryptography from 48.0.0 to 48.0.1 (#67)
dependabot[bot] Jun 20, 2026
d3dcc08
chore(deps): bump actions/checkout from 6.0.3 to 7.0.0 (#68)
dependabot[bot] Jul 2, 2026
5712dfd
chore(deps): bump softprops/action-gh-release from 3.0.0 to 3.0.1 (#69)
dependabot[bot] Jul 2, 2026
b64d982
chore(deps): bump trufflesecurity/trufflehog from 3.95.5 to 3.95.6 (#70)
dependabot[bot] Jul 2, 2026
dbd4e3f
codex/managed-context-sdk (#65)
alain-sv Jul 2, 2026
665ef50
✨ feat(contracts): add V2ContextAssignment for context.assign (#71)
alain-sv Jul 2, 2026
ec535d1
feat: bump version to1.3.0 and update deps; iterate nested (#73)
alain-sv Jul 2, 2026
4e8fc0f
changelog
alain-sv Jul 2, 2026
a09ef1a
chore(deps): bump actions/setup-python from 6.2.0 to 6.3.0 (#75)
dependabot[bot] Jul 7, 2026
6a53535
chore(deps): bump trufflesecurity/trufflehog from 3.95.6 to 3.95.7 (#76)
dependabot[bot] Jul 7, 2026
9bf38b0
Merge branch 'main' into develop
alain-sv Jul 7, 2026
fe1d11d
security: review summary (redacted) + safe P0/P1 hardening (#77)
alain-sv Jul 7, 2026
7cdb2d9
chore(deps): bump trufflesecurity/trufflehog from 3.95.7 to 3.95.9 (#81)
dependabot[bot] Aug 26, 2026
a0453f0
chore(deps): bump softprops/action-gh-release from 3.0.1 to 3.0.2 (#82)
dependabot[bot] Aug 26, 2026
705bddb
chore(deps): bump astral-sh/setup-uv from 8.2.0 to 8.3.2 (#83)
dependabot[bot] Aug 26, 2026
334da0e
chore(deps): bump pyasn1 from 0.6.3 to 0.6.4 (#84)
dependabot[bot] Aug 26, 2026
1dfad10
chore(deps): bump actions/setup-python from 6.3.0 to 7.0.0 (#85)
dependabot[bot] Aug 26, 2026
d373ff6
chore(deps): bump pypa/gh-action-pypi-publish from 1.14.0 to 1.14.1 (…
dependabot[bot] Aug 26, 2026
b14aaaf
chore(deps): bump cryptography from 49.0.0 to 50.0.0 (#87)
dependabot[bot] Aug 26, 2026
96c2789
feat: add generic job setup contract (#89)
alain-sv Aug 26, 2026
9b0e72a
doc
alain-sv Aug 28, 2026
595f33a
Merge branch 'main' into develop
alain-sv Aug 28, 2026
18bb78e
chore: sync main back to develop (v1.5.0)
alain-sv Aug 28, 2026
fcb3238
changelog update
alain-sv Aug 28, 2026
628eb36
✨ feat(contracts): declare action scope and mutability (#92) (#93)
alain-sv Aug 30, 2026
9cb7c4a
[MINOR] chore: merge develop to main
alain-sv Aug 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ Reference specific personas when requesting work:
- In the matrix **build** job, `astral-sh/setup-uv` sets `cache-suffix: py-${{ matrix.python-version }}` so parallel Python versions do not race on the same GitHub Actions cache reservation.
- `@singleton` (from `supervaizer.common`) replaces the decorated class name with a function at import time; modules that annotate with that class in unions (e.g. `StorageManager | None` in `storage.py`) need `from __future__ import annotations` or class-body evaluation raises `TypeError`.
- `UTC` lives on the `datetime` module (`from datetime import UTC`), not on `datetime.datetime`; use `datetime.now(UTC)`, not `datetime.now(datetime.UTC)` (the latter raises `AttributeError` at runtime).
- `just ship` bumps version in CI after merge to `main`, not in the ship PR itself; the publish job waits on GitHub Environment `pypi` approval; bump lands as `chore(release): vX.Y.Z`. After that, `just ship-reconcile` merges `main` back into `develop`.
- Do not re-run a failed `publish-pypi` workflow after the bump commit is already on `main` — it would bump again. Pushing other commits to `main` also retriggers publish with the default minor bump.
- hatchling ≥1.32 emits Metadata-Version 2.5; `pypa/gh-action-pypi-publish` must be ≥v1.14.2, pinned to the peeled tag commit SHA (not the annotated-tag object SHA).

## Security and Supply-Chain Rules

Expand Down
40 changes: 38 additions & 2 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,30 @@ All notable changes to this project will be documented in this file.

## [Unreleased]

### Fixed
### Added

- **PyPI publish (Metadata 2.5)** — Pin `pypa/gh-action-pypi-publish` to v1.14.2 so hatchling ≥1.32 wheels upload. Skip version bump unless the triggering commit has `[MAJOR]`/`[MINOR]`/`[PATCH]`.
- **Declared action scope and mutability (#92)** — `V2AgentCapabilities.actions` is now `list[V2ActionDefinition]` instead of an opaque `list[str]`. Each action declares `id`, `mutating` (does invoking it change agent-side state?), and `scope` (`workspace` / `mission` / `job`), so a consumer can authorize and group actions without pattern-matching the identifier. `id` is caller-supplied at invocation time, so deriving an authorization decision from it puts that decision in the caller's hands.

Plain strings are still accepted everywhere a list of actions is taken — in `build_v2_agent_registration(actions=...)` and when validating a registration payload — and coerce to `mutating=True, scope="job"`, the fail-closed reading that matches today's behaviour. Only the serialized form changes: `capabilities.actions` now emits objects. Consumers must accept both, because agents pinned to older Supervaizer releases keep sending bare strings. No protocol version discriminates the two shapes: `versions.a2ui_version` and `versions.a2a_version` cover the surface catalog and the A2A protocol, not the registration payload.

The builder derives the metadata from the definition each action comes from: resource actions take `V2ResourceDefinition.scope`, dataset queries are `mutating=False`, `V2JobSetupPolicy.preview_action` is `mutating=False`, and workspace binding actions are `workspace`-scoped. Resource operation ids are freeform, so operations stay `mutating=True` unless the agent declares otherwise.

Metadata precedence is explicit > derived > bare: an explicit `V2ActionDefinition` in `actions=` overrides the derived metadata — that is how a job-scoped `resource.invoice.reconcile` on a workspace-scoped resource is declared — while a bare id string declares nothing and defers to the definition it was derived from. Precedence is about metadata, not position: an id declared both ways within `actions=` keeps the explicit metadata regardless of which form comes first, and the earlier mention still fixes the order.

- **`V2DatasetDefinition.scope`** — Mirrors `V2ResourceDefinition.scope` (`workspace` / `mission` / `job`, defaulting to `workspace`) so dataset query actions carry a declared scope rather than an assumed one.

- **`V2AwaitingState.reopenable`** — Declares whether an already-answered awaiting step may be reopened and resubmitted with edited values. Defaults to `False`; previously consumers inferred this from a substring of `surface`.

### Tests

`just test`

| Status | Count |
| ---------- | ----- |
| ✅ Passed | 698 |
| 🤔 Skipped | 0 |
| 🔴 Failed | 0 |
| ⏱️ in | 67s |

## [1.5.0] - 2026-08-28

Expand All @@ -28,6 +49,21 @@ All notable changes to this project will be documented in this file.

- **Regenerated model reference and OpenAPI** — `docs/model_reference/` and `docs/api/openapi.json` were rebuilt from the current models, picking up the job setup contract along with accumulated drift since `0.20.1`. `V2JobSetupPolicy` is now declared before `V2JobPolicy` so the public reference renders the real type instead of a `ForwardRef`.

### Fixed

- **PyPI publish (Metadata 2.5)** — Pin `pypa/gh-action-pypi-publish` to v1.14.2 so hatchling ≥1.32 wheels upload. Skip version bump unless the triggering commit has `[MAJOR]`/`[MINOR]`/`[PATCH]`.

### Tests

`just test`

| Status | Count |
| ---------- | ----- |
| ✅ Passed | 691 |
| 🤔 Skipped | 0 |
| 🔴 Failed | 0 |
| ⏱️ in | 65s |

## [1.4.0] - 2026-07-07

### Added
Expand Down
4 changes: 2 additions & 2 deletions docs/api/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"openapi": "3.1.0",
"info": {
"title": "Supervaize API",
"description": "API version: v1 Controller version: 1.3.1\n\nAPI for controlling and managing Supervaize agents. \n\nMore information at [https://doc.supervaize.com](https://doc.supervaize.com)\n\n## Authentication\n\nSome endpoints require API key authentication. Protected endpoints expect the API key in the X-API-Key header.\n\n[Swagger](/docs)\n[Redoc](/redoc)\n[OpenAPI](/openapi.json)\n",
"description": "API version: v1 Controller version: 1.5.0\n\nAPI for controlling and managing Supervaize agents. \n\nMore information at [https://doc.supervaize.com](https://doc.supervaize.com)\n\n## Authentication\n\nSome endpoints require API key authentication. Protected endpoints expect the API key in the X-API-Key header.\n\n[Swagger](/docs)\n[Redoc](/redoc)\n[OpenAPI](/openapi.json)\n",
"termsOfService": "https://supervaize.com/terms/",
"contact": {
"name": "Support Team",
Expand Down Expand Up @@ -4187,7 +4187,7 @@
"type": "string",
"format": "date-time",
"title": "Timestamp",
"default": "2026-08-26T17:21:02.106370"
"default": "2026-08-29T19:33:56.088920"
},
"status_code": {
"type": "integer",
Expand Down
4 changes: 2 additions & 2 deletions docs/model_reference/model_core.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Model Reference Core

**Version:** 1.3.1
**Version:** 1.5.0

### `account.Account`

Expand Down Expand Up @@ -443,4 +443,4 @@ public_url: full url (including scheme and port) to use for outbound connections
```


*Uploaded on 2026-08-26 17:21:01*
*Uploaded on 2026-08-29 19:33:55*
29 changes: 25 additions & 4 deletions docs/model_reference/model_extra.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Model Reference extra

**Version:** 1.3.1
**Version:** 1.5.0

### `common.SvBaseModel`

Expand Down Expand Up @@ -226,6 +226,25 @@ _No additional fields beyond parent class._
| `dashboards` | `list[contracts.V2DashboardDefinition]` | — | |
| `workspace_binding` | `V2WorkspaceBindingDefinition` | `None` | |

### `contracts.V2ActionDefinition`

**Inherits from:** [`contracts.ContractModel`](#contractscontractmodel)

Declared metadata for one invokable agent action.

Consumers authorize, group and filter actions from these fields. They must
never be inferred from the identifier string: `id` is caller-supplied on
invocation, so pattern-matching it turns an authorization decision into
something the caller controls.

#### Model Fields

| Field | Type | Default | Description |
|---|---|---|---|
| `id` | `str` | **required** | Action identifier used to invoke the action. |
| `mutating` | `bool` | True | Whether invoking the action changes agent-side state. Defaults to True so an undeclared action requires write permission. |
| `scope` | `Literal['workspace', 'mission', 'job']` | 'job' | Context the action operates within. |

### `contracts.V2ActionRequest`

**Inherits from:** [`contracts.ContractModel`](#contractscontractmodel)
Expand Down Expand Up @@ -719,7 +738,7 @@ A2UI-shaped resource import surface consumed by Studio.
| Field | Type | Default | Description |
|---|---|---|---|
| `surfaces` | `list[str]` | — | |
| `actions` | `list[str]` | — | |
| `actions` | `list[contracts.V2ActionDefinition]` | — | |
| `case_lanes` | `list[contracts.V2CaseLaneDefinition]` | — | |
| `artifact_types` | `list[contracts.V2ArtifactTypeDefinition]` | — | |

Expand Down Expand Up @@ -786,6 +805,7 @@ A2UI-shaped resource import surface consumed by Studio.
| `surface` | `str` | **required** | |
| `action` | `str` | **required** | |
| `fields` | `list[contracts.V2AwaitingFieldDefinition]` | — | |
| `reopenable` | `bool` | False | Whether an already-answered step may be reopened and resubmitted with edited values. |

### `contracts.V2CaseLaneDefinition`

Expand Down Expand Up @@ -904,6 +924,7 @@ A2UI-shaped resource import surface consumed by Studio.
| `id` | `str` | **required** | |
| `label` | `str` | **required** | |
| `auto_surface` | `bool` | False | |
| `scope` | `Literal['workspace', 'mission', 'job']` | 'workspace' | |
| `display` | `V2ResourceDisplayDefinition` | `None` | |

### `contracts.V2Effect`
Expand Down Expand Up @@ -1562,7 +1583,7 @@ Standard error response model
| `error` | `str` | **required** | |
| `error_type` | `<enum 'ErrorType'>` | **required** | |
| `detail` | `str` | `None` | |
| `timestamp` | `datetime` | datetime.datetime(2026, 8, 26, 17, 21, 1, 586513) | |
| `timestamp` | `datetime` | datetime.datetime(2026, 8, 29, 19, 33, 55, 605372) | |
| `status_code` | `int` | **required** | |

### `routes.RegistrationRefreshRequest`
Expand Down Expand Up @@ -1630,4 +1651,4 @@ A base class for creating Pydantic models.
| `jti` | `str` | `None` | |


*Uploaded on 2026-08-26 17:21:01*
*Uploaded on 2026-08-29 19:33:55*
1 change: 1 addition & 0 deletions src/supervaizer/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@
"V2A2UIResourceImportDocument",
),
"V2A2UISubmitDefinition": ("supervaizer.contracts", "V2A2UISubmitDefinition"),
"V2ActionDefinition": ("supervaizer.contracts", "V2ActionDefinition"),
"V2AgentCapabilities": ("supervaizer.contracts", "V2AgentCapabilities"),
"V2AgentIdentity": ("supervaizer.contracts", "V2AgentIdentity"),
"V2AgentMethod": ("supervaizer.contracts", "V2AgentMethod"),
Expand Down
16 changes: 10 additions & 6 deletions src/supervaizer/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
from supervaizer.common import ApiSuccess, SvBaseModel, log
from supervaizer.contracts import (
SupervaizerV2AgentRegistrationContract,
V2ActionDefinition,
V2ActionRequest,
V2AgentMethod,
V2AgentMethods,
Expand Down Expand Up @@ -849,13 +850,16 @@ def _validate_supervaizer_v2_identity(self) -> None:
def _apply_v2_method_capabilities(self) -> None:
if self.supervaizer_v2_registration is None or self.v2_methods is None:
return
actions = [
*self.supervaizer_v2_registration.capabilities.actions,
*self.v2_methods.action_ids,
declared = self.supervaizer_v2_registration.capabilities.actions
known_ids = {action.id for action in declared}
self.supervaizer_v2_registration.capabilities.actions = [
*declared,
*(
V2ActionDefinition(id=action_id, mutating=True, scope="job")
for action_id in dict.fromkeys(self.v2_methods.action_ids)
if action_id not in known_ids
),
]
self.supervaizer_v2_registration.capabilities.actions = list(
dict.fromkeys(actions)
)

@property
def slug(self) -> str:
Expand Down
Loading
Loading