---
title: Proposals, approvals and releases
description: How a pack goes from a draft to something agents follow, and how Latest and pinned releases work.
sidebar:
  order: 3
---

A pack passes through four records on its way to agents. Each one points to the one before it, so every decision can be traced back to the exact document text it came from.

```text
source  ->  proposal  ->  approval  ->  release
(the Doc,     (a checked    (a person's    (what agents
 exact         pack draft)   sign-off on    follow)
 version)                    that exact
                             proposal)
```

## Source

A **source** is one exact version of a policy document, read from your connected Google Drive (or added as text through the API). Felspar stores the text and a fingerprint of it. Editing the Doc doesn't change the source: it creates a reason to add a new one. See [Source changes](/guides/source-changes).

## Proposal

A **proposal** is a pack draft that passed `check_pack` and was submitted with `propose_pack` (or `POST /v0/proposals`). Felspar has located every quote in the source, compiled the rules and run the tests. A proposal is not approved and changes nothing for agents.

Any workspace member can propose. Proposals that are never approved expire after 30 days.

## Approval

An **approval** records that a person reviewed a proposal and agrees it says what the company means. On the review page the approver confirms two things, that they reviewed the source, proposed meaning and remaining limitations, and that they reviewed the test expectations and actual results, and adds a note. The approval is bound to the exact proposal: if the proposal changed, it's a different proposal and needs its own review.

Only the workspace owner and approvers can approve. They need their own current access to the source document. Approval records who approved and when. It is the company's judgment that the pack matches the policy; it is not a certification of any external fact.

## Release

A **release** makes an approved pack available to agents. Releasing is a separate click after approval, by the owner or an approver. A release is **immutable**: its content and identity never change. To change a pack, you release a new version. Each release has an ID and a digest (a fingerprint of its exact content), and every decision records both.

## Latest and pinned

Each registered agent follows each of its jobs in one of two ways:

- **Latest** (the default): the agent always gets the job's newest release. When you release a new version, every agent on Latest gets it on its next call. No redeploy, no config change.
- **Pinned**: the agent stays on one chosen release until an owner or approver moves it.

Use Latest unless you have a reason to hold back: a contractual promise tied to one version, a regulated decision that needs a validated version, or trying a new release on one agent first. Pinned agents don't get fixes, so list them when you release and move them on purpose.

Two more rules:

- If the newest release of a job is retired, agents on Latest fall back to the previous released version.
- An agent on Latest can't ask for an older version of its job by name; a pinned agent can only use its pins.

A batch run that decides many cases should keep one release for the whole run, so a release landing mid-run doesn't mix results. Name the release in the request (`expectedReleaseDigest`, or the release-specific route) to hold it.

## How long releases last

A release keeps serving for as long as it is the newest release of its job, or an agent is pinned to it. Felspar keeps the release and its whole chain (source, proposal and approval) for that whole time, with no 30-day cut-off.

When a release stops serving (a newer release replaced it and no agent is pinned to it, or it was retired), Felspar keeps it for a 90-day grace period, then deletes it. Callers that name a superseded release can still use it during the grace period.

Retiring a release, or revoking anything in its chain, ends access to it at once.

## What agents see

An agent's [brief](/reference/mcp-tools#get_job_requirements) comes from the release it would use, and every decision names the release ID and digest that produced it. If a release changes between an agent reading the brief and asking for a decision on a pinned release, Felspar refuses with `release_changed` and the current digest, so the agent can re-read the brief.

## Who can do what

| Step | Member | Approver | Owner | Agent |
| --- | --- | --- | --- | --- |
| Add a source | Yes | Yes | Yes | No |
| Check and propose | Yes | Yes | Yes | No |
| Backtest | Yes | Yes | Yes | No |
| Approve | No | Yes | Yes | No |
| Release | No | Yes | Yes | No |
| Run decisions | Yes | Yes | Yes | Its own jobs only |

Approving and releasing are always a person's own click on the web app. No MCP tool, assistant or agent key can do either. See [Roles and permissions](/guides/roles-and-permissions).
