# Collaborations, requests and reviewed delivery

Cortex collaboration connects people from multiple project teams, their privately authorized agents, selected knowledge, versioned results and existing development systems. Project teams organize work; their names are not company roles or legal authority. Cortex’s existing admission policy still applies.

## Access and authentication

The `/api/collaboration/` routes are Cortex’s same-origin browser backend. They use an existing Hybrid ID sign-in session, admitted Cortex profile and current project participation. Browser writes require the current CSRF token and a stable `Idempotency-Key`. Never copy cookies, account passwords or agent credentials to another person. These browser routes are not a newly activated third-party application bearer API; registered-client platform commissioning remains separate.

Connected personal agents reuse their existing Hybrid ID authorization and protected Cortex MCP connector. Source text, project requests and feedback are reference data, not instructions that override the local agent’s governing instructions. No model, external send or polling schedule is started by creating a project or queuing agent preparation.

## Guided collaboration setup

Choose **New collaboration** (or **Create your first collaboration**) to follow
four small steps: Outcome, People, First request and Review. Outcome templates
are editable starting points. Nothing is saved or invited until the final review.
A confirmed creation records the collaboration and exact profile invitations
atomically. Invitees still choose whether to accept.

Use the completed steps or **Edit outcome**, **Edit people** and **Edit first
request** to revise the setup. Private entries stay in the open setup view; the
final review shows the first request, recipient and date, and requires a fresh
confirmation after edits. Enter in people search finds profiles without advancing
the wizard. Filtered lists offer **Clear filters** when nothing matches.

The optional first request is stored encrypted and private to the creator. It is
not a shared task yet. After a person accepts, choose **Review first request**,
check its current recipient/readers, then send it explicitly. It appears in the
recipient's next actions as a request awaiting acceptance. A saved draft does not
commit another person to work or grant their agent access.

**Draft with my agent** assists with outcome text, an optional email introduction,
the first request, later requests/documents, project edits, questions, updates,
results and private agent guidance. It imports exact text fields only; recipients,
email-address fields, dates, readers, knowledge scope and approvals are excluded.
Applying a draft does not save, invite, send or authorize anything.

Existing people are selected by Cortex name or a canonical personal-profile link.
If you only know an email address, setup can prepare a reviewable introduction
in your own email app. Ask the person to sign in through Hybrid ID and reply with
their Cortex profile link, then invite that exact available profile. This does
not look up an email account, enroll a new Cortex member or send email from Cortex.
The address and introduction are not included in setup API payloads or AI briefs
(the optional introduction text alone can be drafted). Automatic verified-recipient
email invitation/delivery requires a separate supported Identity contract; account
security notifications are not repurposed for it.

`POST /api/collaboration/start` takes the existing session, CSRF token and stable
`Idempotency-Key`, with this exact body:

```json
{
  "title": "Review processing costs",
  "objective": "Confirm the documented conditions before preparing a proposal.",
  "team": "",
  "people": ["<selected Cortex profile ID>"],
  "firstRequest": {
    "title": "Provide the current cost schedule",
    "expected": "Confirm currency, rates, conditions and outstanding questions.",
    "assignee": "<same selected profile ID>",
    "due": ""
  },
  "reviewed": true
}
```

Use `people:[]` to start privately and `firstRequest:null` to prepare the request
later. A first request may leave `assignee` empty until review. At most eight
profiles can be selected for one guided start. Existing membership/blocking,
visibility and synthetic-account boundaries apply. No email or general admission
field is accepted. Only the signed-in creator receives the first-request draft in
project detail; invitations, other members and discovery never receive it.

After an uncertain response, recover only the original operation with
`GET /api/collaboration/start?operation=<original Idempotency-Key>` in the same
owner's authenticated session. This returns the existing resource references,
not a second collaboration. The setup view retains only its operation UUID in
session storage, scoped to the current Cortex profile; no brief or email is stored
there. Do not replace the ID after a timeout. Changed-body retries are rejected.
The wizard does not claim cross-device draft synchronization.

When sending the reviewed first request through the existing task endpoint,
include its current `starterRevision`. Saving the task consumes the private draft
in the same transaction; retries cannot send it twice. A stale draft revision,
revoked membership or archived collaboration stops the operation.

## Human workflow

1. Create a project with a name, objective and optional project-team label.
2. Invite exact Cortex profiles. Invitees can read the invitation summary; they must accept before reading the project roster or its permitted requests.
3. Create a request with one responsible human, an expected result, requested date and explicitly selected additional readers. The requester and assignee are included. Project membership does not expose every request.
4. The recipient accepts, declines, clarifies, proposes a date or proposes another responsible person. Assignment is not acceptance. A newly confirmed recipient must accept responsibility again.
5. Asking for information identifies whose response is needed. Returning the information moves work back to the responsible person. Comments do not silently satisfy a question or approve a result.
6. The responsible person submits a result. The requester accepts it or requests changes. The same records appear in Projects, My next actions and Waiting on others.

Invitations appear in both **Projects** and **My next actions**. Accepting an
invitation opens the collaboration, with an explanation of what to do next.
Joining is separate from accepting responsibility for a request.

Each request shows **Respond → Prepare → Review**, the current next action and
the permitted question or requested changes that need attention. The recipient
can use **Ask a question** before deciding; this posts a shared comment without
accepting responsibility or changing who has the next action. After acceptance,
**Ask for information** explicitly marks the request as waiting for the named
person. **Provide information** returns work to the responsible person.

The requester can request changes and review a resubmission. A completed request
labels its submission **Accepted result**, retaining the exact submitted document
version when one was selected. Request cards show their requester, requested date
and request-update time. These are in-app records, not delivery promises.

Text-writing forms support **Draft with my agent**, including questions asked
before acceptance. The user still selects readers and recipients and explicitly
sends the result. A failed submission keeps its text and selected document in the
open editor. Retrying unchanged uses the original idempotency key in that browser
session. After reload, read the current server state before submitting again;
unsaved text is not promised to survive reload.

Requests can be created from Inbox’s **Request a result** action. It carries only a canonical conversation reference; no messages, protected history or membership are copied. A project or request link is not an access grant.

### Browser request shapes

Use the application’s authenticated `write` helper. These examples are payload shapes, not a request to paste authentication material into a command line.

```js
const project = await write('/api/collaboration/projects', {
  title: 'Processor integration',
  objective: 'Obtain the current cost schedule before preparing a proposal.',
  team: 'Integration team'
});
await write(`/api/collaboration/projects/${project.id}/invite`, {
  profile: selectedCortexProfileId, team: 'Processor team', reviewed: true
});
// The invited person performs this action in their own signed-in session.
await write(`/api/collaboration/projects/${project.id}/participation`, {
  action: 'accept', revision: invitationRevision
});
const request = await write(`/api/collaboration/projects/${project.id}/tasks`, {
  title: 'Current processing cost list',
  expected: 'Provide the currency, current rates and applicable conditions.',
  assignee: selectedCortexProfileId,
  readers: [], due: '', kind: 'request', dependsOn: []
});
```

Use the exact current request revision for each transition. A successful retry uses its original key and unchanged payload. A changed revision returns `409`; reload and review rather than overwrite someone else’s work.

```js
await write(`/api/collaboration/tasks/${request.id}`, {
  action: 'accept', revision: currentRevision
});
await write(`/api/collaboration/tasks/${request.id}`, {
  action: 'wait', revision: currentRevision,
  text: 'Which currency should the schedule use?'
});
// Only the person asked may return this information.
await write(`/api/collaboration/tasks/${request.id}`, {
  action: 'provide-information', revision: currentRevision,
  text: 'Use the currency in the reviewed requirements.'
});
```

`GET /api/collaboration/projects`, `GET /api/collaboration/queue`, and `GET /api/collaboration/projects/{id}/tasks` return bounded pages with `items` and `next`. Pass the returned opaque cursor as `?cursor=...` until `next` is null. Cursors are bound to the signed-in person and selected context. An empty page can still have a next cursor when other requests are outside the caller’s readership. Do not infer complete counts from one page. Project participation is rechecked on every page and request.

## Feedback and screenshots

Request kinds are `request`, `question`, `bug`, and `change`. Optional `feedback` contains a user-selected HTTPS page link, a version label and explicitly included browser/window details. Cortex does not fetch supplied preview links or capture console logs, network logs or session replay automatically.

Screenshots are selected and previewed before sharing. The browser can mark an area and compresses the selected image. The image, description and event commit together under the same retry identity. The original readers remain authoritative after reassignment; a new assignee receives the current brief and future updates, not earlier screenshots, private notes or earlier discussion.

Related requests keep independent status, readership and original feedback. A relationship appears only to people who can read both requests. A link never merges audiences or silently closes a duplicate.

Application-authored project content, screenshots, private preparation and document versions use a purpose-derived encryption key in Cortex’s application store. This is application-level encryption, not owner-held end-to-end encryption or proof of Data Vault archival. Original Data Vault files still require their own current, exact grants. Private notes stay author-only; nothing is automatically copied into shared knowledge or an agent’s approved answer material.

## Updates and private reminders

**Updates** combines new shared activity with private reminders. Request cards
show only shared updates the current participant can read. Private notes and
private reference versions are excluded from these previews. Rollout establishes
a retained activity baseline; older activity is not replayed as a new unread
backlog or asserted to have been read individually. Views refresh when
selected; opening a visible request acknowledges only the exact snapshot shown.
An update arriving afterward stays unread. View markers are private to that
account, not read receipts sent to the other participants.

`item.followUp` in request projections contains `revision`, `remindAt`,
`reminderDue`, `unread`, `updatesPartial`, `latestUpdate` and opaque `through`.
`unread:null` with `updatesPartial:true` means the bounded preview cannot establish
a complete read state. Do not label that as no new updates.

```js
const detail = await api(`/api/collaboration/tasks/${request.id}`);
// Use only after this request's captured update snapshot has been displayed.
await write(`/api/collaboration/tasks/${request.id}/follow-up`, {
  action: 'seen', through: detail.item.followUp.through
});
// A user chooses this future time; the browser converts local input to UTC.
await write(`/api/collaboration/tasks/${request.id}/follow-up`, {
  action: 'remind', revision: detail.item.followUp.revision,
  remindAt: selectedFutureTime.toISOString()
});
// Read the current preference revision before clearing or changing it.
await write(`/api/collaboration/tasks/${request.id}/follow-up`, {
  action: 'clear', revision: currentFollowUpRevision
});
```

Reminder changes retain the original idempotency key and exact body for retry.
Their preference revision is independent of the shared task revision and private
view-marker writes. A `seen` action is monotonic and naturally idempotent; the
captured encrypted view expires after ten minutes and is bound to the current
owner, request and membership. It cannot acknowledge future updates. Reading
uses its own bounded view counter instead of the shared-work editing allowance.

Reminders are encrypted account-private application records. They survive
restart, do not modify anyone else's requested date, and do not email or push.
Due notices appear when the owner returns to Cortex. Closed/archived work and
lost access suppress them. Rejoining does not restore the previous membership's
reminders or request access. Current notification summaries add `updates` and
`reminders`; aggregate monitoring contains no recipient addresses or private text.

Owners can use **Copy invitation link** in **People & teams** for already invited
Cortex profiles. The normal sign-in return opens only the pending summary; it
does not expose the roster or requests until acceptance. A forwarded link gives
an uninvited account no access. Native email invitations remain unavailable:
`GET /api/collaboration/status` reports `emailInvitations.enabled:false` and
`state:"identity-contract-required"`. Existing account-security email is not used
as a collaboration delivery or verified-recipient grant.

The status also reports the required application sender:

```json
{
  "emailInvitations": {
    "enabled": false,
    "state": "identity-contract-required",
    "sender": {
      "name": "Hybrid Cortex",
      "requiredDomain": "hybrid-cortex.com",
      "mailboxConfigured": false
    }
  }
}
```

This describes the sender requirement, not a provisioned mailbox or permission to
send. Cortex-side encrypted intent/reconciliation logic is prepared behind an
internal candidate adapter, with no production adapter or email send endpoint.
It never accepts a caller-selected From address or turns a transport receipt into
project participation. Ordinary confirmed-profile invitations remain available.

## Selected knowledge and document versions

Prepare a `reference` or `deliverable` in a request, select its readers and review the exact text. A reference can remain private to its author. A deliverable must include the requester. Updating a document creates an immutable version; it does not rewrite earlier versions or approvals.

```js
const document = await write(`/api/collaboration/tasks/${request.id}/documents`, {
  revision: 0, kind: 'deliverable', title: 'Interface candidate',
  body: 'Reviewed description and acceptance instructions.',
  previewUrl: 'https://your-preview.example/interface',
  sourceRevision: exactFullCommitSha,
  changeSummary: 'Initial candidate',
  readers: [requesterCortexProfileId], reviewed: true
});
await write(`/api/collaboration/tasks/${request.id}`, {
  action: 'deliver', revision: currentRequestRevision,
  text: 'Please review this exact candidate.',
  document: {id: document.id, version: document.version, digest: document.digest}
});
```

The requester’s acceptance binds the exact submitted version and digest. A newer version invalidates stale acceptance actions and must be submitted for fresh review. An accepted version is retained; further changes use a new version. Prerequisites block starting or delivering dependent work until completed without exposing the content of restricted prerequisite requests.

## Agent preparation

**Prepare with my agent** queues private work for the owner’s connected personal agent. Only the reviewed instruction, optionally selected request brief and exact selected document versions are disclosed. Earlier discussion, private notes and unselected files are excluded.

The existing connector exposes:

- `cortex_sync`: includes current `projectWork` and separately authorized `projectDelivery` metadata.
- `cortex_read_project_work`: read the exact selected preparation context.
- `cortex_propose_project_result`: submit a private proposed result with current approved-knowledge citations, or an empty list when explaining unknowns.
- `cortex_ask_project_owner`: ask a private clarification question.

Owner answers return privately to the runtime. They are not automatically shared or made reusable knowledge. The owner can edit and explicitly share a proposed update or submit it as their result. Shared activity records the agent’s contribution and human review. The responsible human remains accountable; private preparation is not autonomous task acceptance or general project membership for an agent.

Current identity, participation, request revision, selected document versions and approved agent knowledge are rechecked. Changed context stops pending execution. Existing conversation replies retain their propose-first, approved-send workflow; project preparation does not bypass it.

## Developer adapter and release authority

Delivery connections are commissioned by the operator for exact projects, immutable GitHub repository IDs, allowed Cortex approvers, authorized agent runners and permitted environments. Creating a project does not create repository or deployment authority. Production has no new connection until this commissioning is completed.

The adapter can create a draft pull request from an existing branch or submit a GitHub deployment request for an exact commit. A GitHub deployment request requires an existing configured pipeline to execute it; creating the provider record is not successful deployment. GitHub’s environment protection and repository permissions remain authoritative.

Production requests additionally require a completed client review whose accepted current deliverable is bound to the exact commit. Repository approval is separate and expires after 15 minutes. Changes to the task, accepted source, identity or operator policy stop new execution. Revocation cannot recall a request already accepted by an external provider.

The developer uses their own existing GitHub authorization locally. Cortex does not receive or distribute those credentials. Public GitHub evidence is independently queried by repository ID, exact revision, original operation marker and environment. Private repository evidence supports an operator-commissioned GitHub App connection with exact-repository, read-only tokens. That connection is not provisioned by this release; private evidence is never silently trusted from a runner’s report.

### Adapter wiring

Download the [Node adapter](https://hybrid-cortex.com/integrations/cortex-delivery-node.mjs) into your developer tooling. Connect these callbacks to your existing authenticated Cortex MCP client; `callCortex` below represents that client’s parsed tool result.

```js
import {PrivateDeliveryJournal, executeApprovedDelivery}
  from './cortex-delivery-node.mjs';

const result = await executeApprovedDelivery({
  id: originalApprovedOperationId,
  readOperation: id => callCortex('cortex_get_delivery_operation', {id}),
  claimOperation: args => callCortex('cortex_claim_delivery_operation', args),
  reportOperation: args => callCortex('cortex_report_delivery_operation', args),
  journal: new PrivateDeliveryJournal('/your/private/cortex-delivery-journal')
});
```

The supplied `githubCli` implementation uses an already authorized local `gh` installation. `PrivateDeliveryJournal` requires Linux `flock`, an owner-only directory and a filesystem supporting POSIX ownership/permissions. Kernel locks release after a runner crash without deleting the operation journal. Alternatively supply a journal with equivalent `read`, `save`, and exclusive `locked` semantics for your platform.

Before any external write, the adapter durably records a stable attempt and claims the original operation in Cortex. A second process/device cannot submit it under another attempt. On a timeout, retain the journal and reconcile the original provider record. The adapter does not automatically repeat an uncertain write. Do not replace an uncertain operation with a new ID; Cortex blocks a second operation for an unconfirmed revision.

A reported provider ID is not a success assertion. Cortex independently verifies the receipt. Deployment success remains **provider-reported** until a separately configured HTTPS health endpoint returns the exact expected `release` revision. No health configuration means no claim of verified production health. Client acceptance, code review, authorization, provider acceptance and health confirmation remain distinct states.

## Monitoring, notifications and acceptance

Cortex provides in-app action/invitation summaries, scoped project measurements and administrator-only aggregate monitoring. No external email, push message or paid metering is activated. Counts from partial pages are explicitly partial; production adoption or time savings are not inferred from synthetic tests.

- `GET /api/collaboration/notifications`: current in-app actions/invitations, with partial-page indication.
- `GET /api/collaboration/projects/{id}/summary`: measurements for requests the caller can currently read.
- `GET /api/collaboration/monitor`: administrator-only aggregate observation without private content.

Engineering acceptance uses isolated accounts, an isolated local provider and synthetic data. It does not establish real-owner device acceptance, third-party client admission or live customer deployment authority. Those remain explicit commissioning gates.

## Invitation and participation management

**Collaborations → Invitations** lists invitations received by the signed-in
person. Within a collaboration owned by that person, **Invitations** is the
management view for pending, accepted, declined, cancelled, expired and removed
participation. Earlier invitations remain separate after a new invitation.
**People & teams** shows only caller-readable responsibilities, next actions and
selected request access. Search, status, person, requested-date and sorting
controls filter already authorized results in memory; they do not widen access.

The invitation form accepts a person’s name or exact Cortex profile link. Changing
the target or expiry requires a fresh human confirmation. Email lookup is not
available. New invitations expire after seven days by default. The owner may choose one,
seven or thirty days when inviting an exact, available Cortex profile. Existing
invitations keep their original lifetime. Expiry is checked at acceptance,
including after a process restart. Accepting an expired invitation returns `410`;
a stale participation revision returns `409`.

```js
const invited = await write(`/api/collaboration/projects/${projectId}/invite`, {
  profile: reviewedCortexProfileId,
  team: 'Processor team',
  expiresInDays: 7,
  reviewed: true
});
// Private, paginated reads. Follow each opaque next cursor until null.
const received = await api('/api/collaboration/invitations');
const managed = await api(`/api/collaboration/projects/${projectId}/invitations`);
```

The project-scoped history is owner-only. A recipient sees only invitations
addressed to their immutable Cortex profile. Expired or cancelled invitation
returns expose recovery guidance, not the project roster, requests or current
objective. Wrong-account returns do not reveal project content. Sign out from
the header, sign in with the invited account and reopen the link. **Check
invitation again** refreshes a previously expired or cancelled invitation view
once the owner has reviewed a new one. Account creation, verified email ownership
and Cortex admission remain separate Hybrid ID responsibilities.

Each history item has `id`, `project`, `person`, `state`, `current`, the current
participation `revision`, `created`, `updated`, `expires`, `acceptedAt`, `archived`
and `delivery: {channel: 'cortex', email: false}`. `title` is empty after a
recipient's access ends. An empty expiry indicates an original invitation without
an imposed lifetime. Legacy acceptance timestamps are not invented. Pending means
available in Cortex, not that an email was delivered, read or accepted.

A fresh invitation after expiry, decline or cancellation requires owner review
and the current participation revision. It does not restore earlier requests:

```js
await write(`/api/collaboration/projects/${projectId}/invite`, {
  profile: reviewedCortexProfileId,
  revision: currentParticipationRevision,
  team: 'Processor team', expiresInDays: 7, reviewed: true
});
```

For pending invitations, **Copy invitation link** copies a navigation reference
for the owner's chosen communication channel. It sends nothing and grants no
access. Automatic email and email-to-recipient acceptance require the separate
Hybrid ID application-invitation contract. Cortex does not repurpose account
security notices or workspace-role invitation mail. Existing text-drafting
helpers remain available for outcomes, requests, questions, results and reviewed
knowledge; they never select recipients, expiry or access approvals.

### Review removal before changing access

An owner can preview the effect of cancellation or removal. The response contains
only request titles the owner can read, roles, open responsibilities that need a
new recipient (`needsReassignment`), loss of the original requester’s review
authority (`needsNewRequest`), and an encrypted review token. It does not expose private requests
between other teams. Removal nevertheless ends all access under that participation.
Previously received copies cannot be recalled.

```js
const preview = await api(`/api/collaboration/projects/${projectId}/access-review?profile=${encodeURIComponent(profileId)}`);
// Show preview.person and preview.requests, and obtain explicit human confirmation.
await write(`/api/collaboration/projects/${projectId}/participation`, {
  action: 'revoke', profile: profileId,
  revision: preview.revision, accessReview: preview.review
});
```

The ten-minute review token binds the current owner, project, target participation
and request revision snapshot. If participation or work changes, removal returns
`409`; refresh and review again. An unchanged retry uses the original operation
key and payload. The token is not an access credential and cannot authorize
another project or person. Existing non-preview API consumers retain their
membership-revision check; the Cortex UI always uses the reviewed preview.

Participants may explicitly leave using their own current participation revision:

```js
await write(`/api/collaboration/projects/${projectId}/participation`, {
  action: 'leave', revision: myParticipationRevision
});
```

The owner cannot leave; they can archive the collaboration. New participation
after leaving still requires a new invitation and does not revive old requests.

### Edit project-team labels

Team labels organize a collaboration without granting company roles or authority.
Changing a label preserves membership generation and existing request access.
`previousTeam` detects a concurrent edit independently of membership revision:

```js
await write(`/api/collaboration/projects/${projectId}/participation`, {
  action: 'team', profile: profileId, revision: currentParticipationRevision,
  previousTeam: currentTeamLabel, team: 'Delivery team'
});
```

This is an owner-only write for a current active or invited participant in an
active collaboration. All writes keep normal session, admission, CSRF and
original-operation checks. Monitoring adds aggregate recorded/pending invitation
counts, without private content, recipient addresses or billing.

## Connect ChatGPT

In Cortex, open a request and select **Connect an agent**. Choose an existing
Hybrid ID-connected agent and review the sources and discussion it can use.

In ChatGPT, add a custom MCP server with the URL
`https://hybrid-cortex.com/mcp/collaboration` and choose OAuth. Use a workspace
that permits custom MCP servers. The Cortex consent page asks you to select
one request and agent. The connector reads that request's selected context
and submits private drafts for review. Pausing or removing the request
connection ends access. Signing out of the linked Cortex session also ends
access. Connect again to use a different request.

Copy the request link from Cortex and give it to the connected ChatGPT agent,
or configure a published Workspace Agent to receive the work item ID from the
runner. The agent can read that item with `cortex_read_project_work` and return
a private draft with `cortex_propose_project_result`. Keep the repository tool
restricted to the selected repository and a review branch.

The developer runner uses an existing Hybrid ID responder credential and a
Workspace Agent trigger token. Run it as a dedicated user with GitHub access to
the selected repository and its existing deployment workflow. Configure a
Cortex delivery target for the exact project, repository ID, approver, agent,
environment and health endpoint. The health endpoint must report the full
deployed commit. See the deployment operator guide for the runner command.
