# Aport Complete

> Verify a completed task against your APort passport's deliverable contract before marking it done. Enforces acceptance criteria, summary requirements, test status, and reviewer checks deterministically. Use this before calling any task complete.

- Skill: `aporthq-aport-skills/aport-complete` (Agent Skill)
- Install (CLI): `npx skillmds@latest add aporthq-aport-skills/aport-complete`
- Raw SKILL.md: https://api.skillmd.com/api/skills/aporthq-aport-skills/aport-complete/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Productivity
- License: Apache-2.0
- Author: aporthq (https://skillmd.com/u/aporthq-aport-skills)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/aporthq-aport-skills/aport-complete

---


# /aport-complete — Verify Before Done

Your APort passport defines what you must deliver before a task is complete.
This skill enforces that contract. Do not mark any task done without running this first.

## When to use this skill

- Before telling a user "I'm done" or "it's complete"
- Before closing a task, ticket, or GitHub issue
- Before opening a PR and considering work finished
- Before handing off to another agent
- Any time you would otherwise call a task complete

## Prerequisites

You must have an APort passport with a deliverable contract.

If you don't have one, create a passport first:
- **Web:** https://aport.id
- **CLI:** `npx aport-id`
- **Agent skill:** Read https://aport.id/skill and follow the instructions

You need `APORT_AGENT_ID` and optionally `APORT_API_KEY` in your environment.
These are returned when you create and claim your passport, saved to `aport-passport.json`.

## Step 1 — Compile your completion context

Before calling the API, gather:

| Field | Required | How to get it |
|-------|----------|---------------|
| `task_id` | Yes | The task/ticket/issue identifier |
| `output_type` | Yes | `code`, `document`, `analysis`, `plan`, `data`, or `other` |
| `summary` | If passport requires it | Write a clear summary of what you did |
| `tests_passing` | If passport requires it | Run your test suite, report result |
| `author_agent_id` | If reviewer required | Your own `APORT_AGENT_ID` |
| `reviewer_agent_id` | If reviewer required | The `agent_id` of the reviewing agent |
| `criteria_attestations` | Always | One entry per criterion in your passport |
| `output_content` | If scan_output enabled | Your full output (for pattern scanning) |

## Step 2 — Build your attestations

Your passport defines acceptance criteria as a list of descriptions.
Each criterion maps to a `criterion_id` — the description slugified to lowercase
with spaces replaced by hyphens.

Example:
```
Criterion description: "A concrete output artifact must be produced"
criterion_id:          "a-concrete-output-artifact-must-be-produced"
```

For each criterion in your passport, you must submit:
```json
{
  "criterion_id": "a-concrete-output-artifact-must-be-produced",
  "met": true,
  "evidence": "Concrete evidence — a file path, PR URL, CI run id, command output"
}
```

Evidence must be non-empty. "I believe this is met" is not evidence.
Good evidence: `PR #47 at github.com/org/repo/pull/47`
Good evidence: `grep -r "TODO" src/ returned 0 results`
Good evidence: `CI run #1234 passed — https://ci.example.com/runs/1234`

## Step 3 — Call the verify endpoint

```
POST https://aport.io/api/verify/policy/deliverable.task.complete.v1
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

{
  "context": {
    "agent_id": "YOUR_APORT_AGENT_ID",
    "task_id": "TASK_IDENTIFIER",
    "output_type": "code",
    "author_agent_id": "YOUR_APORT_AGENT_ID",
    "summary": "What you did — must meet minimum word count in your passport",
    "tests_passing": true,
    "criteria_attestations": [
      {
        "criterion_id": "criterion-slug-here",
        "met": true,
        "evidence": "Concrete evidence string"
      }
    ]
  }
}
```

The `Authorization` header is optional but recommended — it links the decision to your identity for tracking.

Note: `agent_id` goes inside `context`, alongside the policy-specific fields.

## Step 4 — Handle the response

### ALLOW response
```json
{
  "decision": {
    "decision_id": "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx",
    "allow": true,
    "reasons": [
      { "code": "capability_verified", "message": "...", "severity": "info" }
    ],
    "created_at": "2026-03-13T09:00:00Z",
    "signature": "...",
    "policy_id": "deliverable.task.complete.v1",
    "agent_id": "ap_..."
  },
  "request_id": "..."
}
```
The task is done. You may mark it complete, close the ticket, open the PR.
Reference the `decision_id` in your completion message for the audit trail.

### DENY response
```json
{
  "decision": {
    "decision_id": "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx",
    "allow": false,
    "reasons": [
      { "code": "oap.summary_insufficient", "message": "Summary is required...", "severity": "error" }
    ]
  },
  "request_id": "..."
}
```

Do not mark the task done. Check `decision.reasons[].code` for the deny code. Fix the issue and retry.

| deny_code | What it means | What to do |
|-----------|--------------|------------|
| `oap.summary_insufficient` | Summary too short or missing | Rewrite summary with more detail |
| `oap.tests_not_passing` | Tests failing or not submitted | Fix tests, resubmit with `tests_passing: true` |
| `oap.criteria_not_met` | A criterion has `met: false` | Resolve the criterion, re-attest |
| `oap.evidence_missing` | An attestation has no evidence | Add a concrete evidence string |
| `oap.criteria_incomplete` | Missing attestation for a criterion | Add attestations for all passport criteria |
| `oap.self_review_not_allowed` | Reviewer and author are the same | Get a different agent to review |
| `oap.blocked_pattern_detected` | Output contains blocked content | Remove blocked patterns, resubmit |
| `oap.passport_suspended` | Passport is suspended | Contact APort — your passport needs attention |
| `oap.unknown_capability` | Passport missing deliverable.task.complete | Create a new passport with a deliverable contract |

## Step 5 — Announce completion

Once you receive `allow: true`, tell the user:
- What you completed
- The decision_id (if they want the audit trail)
- Any next steps

Do not say "done" before receiving `allow: true`. The contract defines done, not you.

## Retry behaviour

The deny_code is designed for autonomous retry. If you receive:

- `oap.summary_insufficient` → rewrite your summary and retry immediately
- `oap.evidence_missing` → add evidence strings and retry immediately
- `oap.tests_not_passing` → attempt to fix the failing tests, then retry
- `oap.blocked_pattern_detected` → remove the blocked content, then retry
- `oap.self_review_not_allowed` → this requires another agent — ask the user or route to reviewer
- `oap.criteria_not_met` → attempt to resolve the criterion, then retry

Maximum retries: 3. After 3 denials on the same task, surface the issue to the user.
Do not loop indefinitely.

## Links

- Create a passport: https://aport.id (web) or `npx aport-id` (CLI) or https://aport.id/skill (agent)
- Your passport: https://aport.id/passport/YOUR_SLUG
- Verify a decision: GET https://aport.io/api/verify/decisions/get/DECISION_ID
- API docs: https://aport.io/api/documentation

