Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
69 changes: 69 additions & 0 deletions .github/workflows/request-promotion.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
name: request-promotion

on:
workflow_dispatch:
inputs:
sha:
description: Commit SHA to promote; defaults to the current ref
required: false
type: string
workflow_run:
workflows: [ci]
types: [completed]

permissions:
contents: read

concurrency:
group: request-promotion-${{ github.event.workflow_run.head_sha || inputs.sha || github.sha }}
cancel-in-progress: false

jobs:
request:
if: >
github.event_name == 'workflow_dispatch' ||
(github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.head_branch == 'main' &&
github.event.workflow_run.event == 'push')
runs-on: [self-hosted, linux, x64, hyrule-public-pr]
timeout-minutes: 5
steps:
- name: Generate promotion app token
id: app-token
uses: actions/create-github-app-token@v2
with:
app-id: ${{ secrets.PROMOTION_APP_ID }}
private-key: ${{ secrets.PROMOTION_APP_PRIVATE_KEY }}
owner: AS215932
repositories: network-operations

- name: Request network-operations promotion PR
env:
GH_TOKEN: ${{ github.token }}
PROMOTION_TOKEN: ${{ steps.app-token.outputs.token }}
REPOSITORY: ${{ github.repository }}
INPUT_SHA: ${{ inputs.sha }}
WORKFLOW_RUN_SHA: ${{ github.event.workflow_run.head_sha }}
run: |
set -euo pipefail
app="${REPOSITORY#AS215932/}"
SHA="${INPUT_SHA:-${WORKFLOW_RUN_SHA:-${GITHUB_SHA}}}"
SHA="${SHA,,}"

if ! [[ "$SHA" =~ ^[0-9a-f]{40}$ ]]; then
echo "::error::promotion SHA must be a 40-character hex commit SHA"
exit 1
fi

canonical="$(gh api "repos/${REPOSITORY}/commits/${SHA}" --jq .sha)"
if [ "$canonical" != "$SHA" ]; then
echo "::error::commit ${SHA} was not found in ${REPOSITORY}"
exit 1
fi

GH_TOKEN="$PROMOTION_TOKEN" gh api --method POST repos/AS215932/network-operations/dispatches \
-f event_type=app-promote \
-f "client_payload[repository]=$REPOSITORY" \
-f "client_payload[sha]=$SHA" \
-f "client_payload[title]=Promote ${app} ${SHA:0:7}" \
-f "client_payload[impact]=Automated promotion request from ${REPOSITORY}@${SHA}."
31 changes: 23 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# agent-core

Shared, dependency-light **typed contracts** for the AS215932 Agent Runtime Framework.
Shared, dependency-light **typed contracts** and optional coordination services for
the AS215932 Agent Runtime Framework.

This is the **§31 safe milestone** (Phase 1) of the framework consolidation described in
`../docs/migration/first-safe-milestone.md`. It introduces standard contracts **without
changing any existing loop's behavior**:
The base installation remains contract-only; service and HTTP dependencies are isolated
behind extras:

- `agent_core/contracts/` — pydantic v2 models (JSON-serializable, schema-versioned).
Importing them pulls in **only pydantic** (no langgraph / pydantic-ai / db).
Expand All @@ -16,13 +16,28 @@ changing any existing loop's behavior**:
by tests only**; not wired into any loop's runtime.
- `agent_core/contracts/graphs/` — *descriptive* draft `GraphSpec`s of the loops' current
LangGraph topology (no compiler yet).
- `agent_core/coordination/` — signed LHP-v2 HTTP client used identically by SOC, NOC,
Engineering, Knowledge, and the Agentic Observatory.
- `agent_core/coordinator/` — optional FastAPI/Postgres coordination service. It owns
handoff state, claims, immutable approvals, verification transitions, and sanitized
case projections; it does not own private loop state or replace the trace collector.

## Scope

In: contracts, adapters (test-only), draft GraphSpecs, deterministic arbitration helper,
tests, CI.
Out (later phases): runtime, GraphSpec compiler, model router, tool/MCP registries,
memory store, learning substrate, judges, policy gates, control-plane API/GUI.
In: contracts, adapters, draft GraphSpecs, deterministic arbitration, the optional
coordinator/client, tests, and CI. Out: a universal agent runtime, GraphSpec compiler,
model router, tool/MCP registry, or direct production executor.

## Coordinator

```bash
uv run --extra coordinator agent-core-coordinator
```

Production requires `HYRULE_COORDINATOR_DATABASE_URL` and a JSON map of per-loop key
IDs/secrets in `HYRULE_COORDINATOR_LOOP_KEYS_JSON`. The service binds to port `8771` by
default. Every protected request is signed with the generic `X-Agent-Loop-*` headers;
the shared `CoordinatorClient` handles canonical encoding and signing.

## Develop

Expand Down
2 changes: 1 addition & 1 deletion agent_core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

from __future__ import annotations

__version__ = "0.7.0"
__version__ = "0.9.0"
31 changes: 31 additions & 0 deletions agent_core/contracts/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,22 @@
PolicyGateResult,
)
from agent_core.contracts.context import RunContext, RuntimeContext
from agent_core.contracts.coordination import (
CORE_LOOPS,
LHP_VERSION,
ApprovalRecord,
CaseProjection,
HandoffEnvelope,
HandoffEvent,
HandoffEventType,
HandoffRecord,
HandoffResult,
HandoffStatus,
LoopHeartbeat,
LoopRegistration,
ProbePlan,
VerificationResult,
)
from agent_core.contracts.decision import DecisionPacket
from agent_core.contracts.errors import ErrorEnvelope
from agent_core.contracts.evidence import EvidencePacket, SourceRef
Expand Down Expand Up @@ -111,6 +127,21 @@
"GovernanceControls",
"LoopDecisionEnvelope",
"CrossLoopArbiterDecision",
# LHP-v2 coordination
"CORE_LOOPS",
"LHP_VERSION",
"LoopRegistration",
"LoopHeartbeat",
"CaseProjection",
"HandoffEnvelope",
"HandoffEvent",
"HandoffEventType",
"HandoffResult",
"VerificationResult",
"ApprovalRecord",
"HandoffRecord",
"HandoffStatus",
"ProbePlan",
# observatory
"ObservatoryLink",
"ActorRef",
Expand Down
Loading
Loading