Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
066b11a
Add Project repository associations and non-destructive Owner closure
zy95-12 Nov 2, 2026
61e0abc
Separate personal-agent identities from Project participations
zy95-12 Nov 2, 2026
6eeba41
Authenticate scoped personal-agent connections with existing delegati…
zy95-12 Nov 2, 2026
b4fa8de
Preserve Task-role definitions and latest SDK session across retries
zy95-12 Nov 2, 2026
439a41c
Expose durable handoff contracts and private consultation flows
zy95-12 Nov 2, 2026
a9ff63b
Bound role context and retain scoped memory and working summaries
zy95-12 Nov 2, 2026
6ebc706
Cover scoped memory source pages and record real SDK continuation val…
zy95-12 Nov 2, 2026
4101275
Deliver fresh native Chief job context in the resident Session turn
zy95-12 Nov 2, 2026
70fbe82
Admit Project Tasks through Chief and resume parents after child results
zy95-12 Nov 2, 2026
4826723
Adjudicate dependency exceptions and admit verified child integration…
zy95-12 Nov 2, 2026
dba40f8
Require approved durable Project role changes
zy95-12 Nov 3, 2026
3e90554
Integrate approved role governance with personal agent identities
zy95-12 Nov 3, 2026
3629495
Integrate approved roles with current personal agent authorization
zy95-12 Nov 3, 2026
cbab78a
Merge branch 'feat/2183-agent-auth' into feat/2184-execution-lifecycle
zy95-12 Nov 3, 2026
a11696d
Require native execution quiescence before releasing Task context
zy95-12 Nov 3, 2026
f404153
Execute custom Project roles with pinned capability policies
zy95-12 Nov 3, 2026
32f7941
Activate exact native context before resuming pool handoffs
zy95-12 Nov 3, 2026
3f7fe22
Require consistent native exit proof across pool and supervisor recovery
zy95-12 Nov 3, 2026
29f0e02
Revalidate retained role execution and stop revoked claims through ex…
zy95-12 Nov 3, 2026
36210b9
Compose current execution and role governance with durable handoff co…
zy95-12 Nov 3, 2026
c16a25e
Compose bounded role context with current native execution and govern…
zy95-12 Nov 3, 2026
54a6bb5
Compose canonical Task waits with retained roles and fence changed re…
zy95-12 Nov 3, 2026
b77e598
Sync delivery integration ancestry for #2226
zy95-12 Nov 3, 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
14 changes: 14 additions & 0 deletions LESSONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -655,6 +655,16 @@ old active label and verifies Task/Attempt/generation and blocked state survive.

2026-11-03 Seen 1×: a resident native Session may retain its system definition after bot metadata changes. Put each current job protocol/facts in the actual turn input; keep prior context historical and preserve the Session. The explicit Task scope fence caught stale-job output during #2179 admission verification.

### 2026-11-03 — A child result is neither parent completion nor integration

Seen 1× while implementing #2179. Reusing old group aggregation would accept cancelled children and close the parent automatically. Project waits require Chief-adjudicated child outcomes and keep an explicit parent integration continuation. Releasing workers must also free the parent execution quota; an unknown lease still consumes it. Resuming the old claim must not manufacture a second source work-summary revision for the same completed execution.

#2179 acceptance review: compare the complete requirements revision, not just title/criteria, before closing a candidate. A scope-only change still invalidates old evidence. A failed Attempt blocks the new Task commitment; it cannot silently become a terminal Task failure.

#2179 policy-budget regression: active memory plus historical progress reports exceeded the existing complete-role-policy budget. Retain active invariants, archive dated candidate/run narratives with a source link, and preserve their full text. Do not raise the context ceiling, silently truncate required guidance, or reuse archived test counts as current evidence.

#2179 integration regression: `git rev-parse MERGE_HEAD` returns only the first parent of an octopus merge. Validate every bounded registered MERGE_HEAD entry before sealing; an admitted first source cannot conceal an unapproved second parent. Preserve the staged index on rejection.


### 2026-11-03 — Public Chief cannot borrow its approver's identity

Expand Down Expand Up @@ -733,3 +743,7 @@ Seen 1× (composed role governance/contract regression). Confirming an old sourc
### 2026-11-03 — Logical role IDs are not execution carrier IDs

Seen 1× (composed actual DSH native input failure). A canonical claim keeps the logical Bot in botId and the temporary executor in workerId. Context input fences must compare the carrier with workerId; conflating them sends healthy work to Chief admission failure before any execution.

### 2026-11-03 — Fence old-plan decisions as well as external effects

Seen 1× (late Task requirement response regression). Stopping on the next scheduler pass alone leaves a window for an old turn to transfer/split. Bind current claims to the Task requirement revision and recheck after authorization; use actual old Attempt snapshot revisions for compatible prior claims. Keep publication evidence fences too.
212 changes: 48 additions & 164 deletions PROJECT.md

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,14 @@ verification must name exact runtime source hashes, not borrow deterministic tes

#2177 follow-up: validate two sequential native Chief jobs against fresh per-turn facts while retaining the same resident Session; dependent Task admission runtime acceptance remains #2179.

### 2026-11-03 — Project Task contract (#2179)

New shared Tasks have Chief admission and versioned requirements. Existing Task/pool/Effects records carry independent child proposals, a released parent wait and one stable resume Handoff; child failure/cancellation never satisfies a wait. Original parent role context and workspaces are retained. Raw legacy board transitions cannot bypass the new contract, while persisted pre-contract Tasks keep their original semantics. Chief callback, rollback, exit and duplicate-resume tests are distinct from real-provider full child integration acceptance; native restore2184, storage2182 and public event/receipt2185 dependencies remain open. README simplification2189 remains last.

#2179 retains legacy Workflow delivery compatibility while requiring Chief admission for new Tasks on either path. Chief runtime quota is independent of execution slots; waiting parent lease state remains authoritative. Full real-provider child integration and native physical restoration are still dependency acceptance, not implied by deterministic runtime tests.

#2179 follow-up: Chief dependency waivers/substitutions retain exact outcome versions and explicit judgement evidence. Accepted child code enters the existing durable integration gates before parent execution; source admission is not merging or parent acceptance. Actual Git multi-parent sealing tests use deterministic child acceptance fixtures. Full real-provider parallel collaboration and native physical restoration remain pending.

Native prior-host reconciliation now reuses verified supervisor process-group facts; native v2 registered-work/lineage and shared adapter-exit regressions guard against premature initiative transfer. In-flight current-rights abort and composed-stack acceptance remain active.

Canonical ongoing role/resource authority checks now reuse native step/SDK input and the existing scheduler + pool stop. Frozen role context remains stable; current revoked rights stop execution, with unknown exit held. Compose descendants and verify parent Task resume/API projections next.
1 change: 1 addition & 0 deletions changelog.d/2179.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add Chief-admitted Project Task contracts, versioned requirements and parallel child waits that resume the original parent role through existing pools and Effects. Preserve pre-contract delivery behavior and refuse legacy board bypasses for new Tasks. Add versioned Chief dependency waiver/replacement decisions and private durable accepted-child source admission; preserve parent integration/acceptance gates and verify every pending Git merge parent. Compose approved custom role capabilities and native continuation; changing canonical requirements stops the old Attempt before successor execution, while preserving its Task-role Session.
3 changes: 2 additions & 1 deletion core/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import * as projectChiefControl from './src/host/project-chief-control.js'
import * as projectScheduledTasks from './src/host/project-scheduled-tasks.js'
import * as projectDelegations from './src/host/project-delegations.js'
import * as projectGithubRead from './src/host/project-github-read.js'
import * as projectTaskLifecycle from './src/host/project-task-lifecycle.js'
import * as projectPools from './src/host/project-pools.js'
import * as projectScheduler from './src/host/project-scheduler.js'
import * as workbenchState from './src/host/workbench-state.js'
Expand Down Expand Up @@ -82,7 +83,7 @@ export const inject = ['llm', 'tools', 'systemPrompt', 'sessionController', 'ses
// the functions other modules call; they call them through `rt` at run time, never during
// install. Listeners run and tools are listed in registration order, so this order holds:
// usage meters model requests after every listener that rewrites them.
const MODULES = [diagnostics, store, projectEffects, projectInputs, harness, memberAuth, platformIdentity, projectAccess, projectDevelopment, projectExecutionBoundary, projectResources, projectHarness, projectRuntimeSetup, projectDelivery, projectDelegations, projectAgents, projectCredentials, projectGithubRead, projectPools, projectScheduledTasks, projectSources, projectChiefControl, projectScheduler, workbenchState, authz, personalAgentAuth, models, permissions, turns, busyAck, steeringInterrupt, delivery, roster, folders, agents, prompt, timeContext, tools, decisions, projectState, meetings, chatIndex, groups, roomMembership, reach, tasks, projectBoard, taskDrive, approvals, resume, memory, parts, images, secrets, connectors, connectorAccess, capabilities, schedules, projectAssistant, projectChief, projectTeam, automationDefault, browser, usage, update, dshUpdate, hooks, remoteChat, workflowStore, channel]
const MODULES = [diagnostics, store, projectEffects, projectTaskLifecycle, projectInputs, harness, memberAuth, platformIdentity, projectAccess, projectDevelopment, projectExecutionBoundary, projectResources, projectHarness, projectRuntimeSetup, projectDelivery, projectDelegations, projectAgents, projectCredentials, projectGithubRead, projectPools, projectScheduledTasks, projectSources, projectChiefControl, projectScheduler, workbenchState, authz, personalAgentAuth, models, permissions, turns, busyAck, steeringInterrupt, delivery, roster, folders, agents, prompt, timeContext, tools, decisions, projectState, meetings, chatIndex, groups, roomMembership, reach, tasks, projectBoard, taskDrive, approvals, resume, memory, parts, images, secrets, connectors, connectorAccess, capabilities, schedules, projectAssistant, projectChief, projectTeam, automationDefault, browser, usage, update, dshUpdate, hooks, remoteChat, workflowStore, channel]

export function apply(ctx, config = {}) {
const rt = createRuntime(ctx, config)
Expand Down
4 changes: 3 additions & 1 deletion core/src/host/project-access.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Project-scoped human authorization. Instance-wide and private Bot APIs keep their own gates.
import { releasedParentWait } from './project-scheduler.js'
import { createHash, randomBytes } from 'node:crypto'
import { ownEntry, setEntry } from './store.js'
import { roleOf, rolesOf } from '../shared/project-policy.js'
Expand Down Expand Up @@ -38,7 +39,7 @@ export function install(rt) {
defaultBranch: project.defaultBranch ?? 'main', workDir: project.workDir ?? null,
status: project.status, createdAt: project.createdAt, updatedAt: project.updatedAt,
role: roleOf(project, actor?.memberId), quota: project.quota ?? { maxConcurrent: 2 } })
const activeRuns = id => Object.values(state.projectExecutions ?? {}).filter(run => run.projectId === id && ['running', 'queued', 'paused', 'working'].includes(run.status))
const activeRuns = id => Object.values(state.projectExecutions ?? {}).filter(run => run.projectId === id && run.kind !== 'chief-control' && !releasedParentWait(state, run.attemptId) && ['running', 'queued', 'paused', 'working'].includes(run.status))
function safeDetail(id, actor) {
const detail = rt.projects.detail(id, actor)
return { ...detail, project: safeProject(detail.project, actor), permissions: {
Expand Down Expand Up @@ -79,6 +80,7 @@ export function install(rt) {
const task = ownEntry(state.tasks, String(body.taskId ?? ''))
if (!task || task.projectId !== id) throw refusal('A Project Run needs a Task from this Project')
rt.requireProjectAccess(actor, id, 'task-write', task)
rt.projectTaskLifecycle?.requireExecutable(task)
payload = { workflowId: item.id, taskId: task.id, title: task.title, brief: task.note ?? task.title, projectId: id, callerBotId: project.chief?.botId }
const existing = activeRuns(id).find(run => run.taskId === task.id)
if (existing) {
Expand Down
6 changes: 3 additions & 3 deletions core/src/host/project-agents.js
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ export function createProjectAgents(rt) {
if (existingTask) return structuredClone(existingTask)
const projectTaskKind = body.projectTaskKind ?? 'code'
if (!['code', 'decision', 'release'].includes(projectTaskKind)) throw refuse('Unknown impactful Task kind')
const fields = { title, criteria: clean(body.criteria, 2000), note: clean(body.note, 2000), projectTaskKind }
const fields = { title, criteria: clean(body.criteria, 2000), note: clean(body.note, 2000), impact: clean(body.impact, 2000), scope: clean(body.scope, 2000), projectTaskKind }
if (!canPublish) {
const row = { id: `proposal-${randomUUID()}`, projectId: agent.projectId, memberId: actor.memberId, fields, requestKey, createdAt: Date.now() }
setEntry(proposals(), row.id, row)
Expand Down Expand Up @@ -363,7 +363,7 @@ export function createProjectAgents(rt) {
await rt.save()
const finish = async result => {
try { if (delegations.get(agent.id)?.id !== delegation.id || delegation.revoked) throw refuse('Chief execution was revoked'); await onResult({ ...result, executionEvidence: { ...result.executionEvidence, chiefRunId: runId, carrierGeneration: agent.carrierGeneration } }); agent.lastRequest.phase = result.ok ? 'completed' : 'failed' }
finally { restorePrompt(); if (delegations.get(agent.id)?.id === delegation.id) delegations.delete(agent.id); await rt.save() }
finally { restorePrompt(); if (delegations.get(agent.id)?.id === delegation.id) delegations.delete(agent.id); await rt.save(); rt.projectScheduler?.wake() }
}
delegation.finishChiefJob = finish
try {
Expand Down Expand Up @@ -790,7 +790,7 @@ export function install(rt) {
['project_agent_roles', { role: { type: 'string' }, offset: { type: 'number' }, expectedSha256: { type: 'string' } }, 'Read the current Project role catalog or one bounded exact role-definition source.', async (args, bot) => { const current = await rt.projectAgents.actorOf(bot); return rt.projectRoleGovernance.catalog({ ...args, projectId: current.agent.projectId }, current.actor) }],
['project_agent_role_propose', { requestId: { type: 'string', required: true }, action: { type: 'string', required: true }, role: { type: 'string', required: true }, reason: { type: 'string', required: true }, fields: { type: 'object', properties: {}, additionalProperties: true } }, 'Resident Chief proposes add/update/remove of a role. A separate current Maintainer/Owner must approve; this tool cannot apply or approve it.', async (args, bot) => rt.projectAgents.proposeRole(bot, args)],
['project_agent_memory', { text: { type: 'string', required: true } }, 'Save a private user/project note; never publish it.', async (args, bot) => rt.projectAgents.memory(bot, args.text)],
['project_agent_task', { title: { type: 'string', required: true }, criteria: { type: 'string' }, note: { type: 'string' }, projectTaskKind: { type: 'string', description: 'code, decision or release; ordinary questions are conversation handoffs' } }, 'Propose a Task privately, or create from the current public request.', async (args, bot) => rt.projectAgents.task(bot, args)],
['project_agent_task', { title: { type: 'string', required: true }, criteria: { type: 'string' }, impact: { type: 'string' }, scope: { type: 'string' }, note: { type: 'string' }, projectTaskKind: { type: 'string', description: 'code, decision or release; ordinary questions are conversation handoffs' } }, 'Propose a Task privately, or create from the current public request.', async (args, bot) => rt.projectAgents.task(bot, args)],
['project_agent_suggest_closure', { reason: { type: 'string', required: true } }, 'Recommend Project closure without creating a Task or granting closure rights. The Owner must personally double-confirm.', async (args, bot) => rt.projectAgents.suggestClosure(bot, args)],
['project_agent_consultations', { operation: { type: 'string' }, consultationId: { type: 'string' }, requestId: { type: 'string' }, text: { type: 'string' }, publish: { type: 'boolean' } }, 'Read your own Chief questions or reply. Safe answers remain private until human approval; watch replies enter the existing Task inbox.', async (args, bot) => rt.projectAgents.agentConsultations(bot, args)],
['project_agent_chief', { text: { type: 'string', required: true }, requestId: { type: 'string', required: true } }, 'Ask Chief an ordinary question without creating a Task. The answer returns to this private conversation.', async (args, bot) => rt.projectAgents.askChief(bot, args)],
Expand Down
Loading
Loading