Skip to content
Merged
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
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,21 @@ date, grouped by `Added` / `Changed` / `Fixed` / `Removed`.

## [Unreleased]

## [2026-07-13] — v0.10.0 · Rich issue rendering & delivery-safe goals

### Added

- **Issue descriptions, comments, and Focus now render rich content consistently.** Direct images and browser-playable videos get bounded previews; supported YouTube, GitHub, Loom, and Figma links get controlled provider cards; every preview can be collapsed, hidden, restored, or opened directly with accessible controls and safe fallbacks.
- **Plan steps now have an obvious issue-like conversation path.** Each step exposes Comment and Ask @agent actions, with the same mention autocomplete used in issue threads. Mentioning an agent wakes canonical issue-backed work with the Goal, Plan, Step, dependency, and operator-comment context.

### Changed

- **Finished execution no longer certifies its own delivery.** When every required step passes, the Plan becomes Completed but the Goal remains Active in outcome review. A signed-in operator must record a delivered-outcome summary and at least one PR, commit, deployment, test, artifact, or other reference before accepting the Goal as Achieved.

### Fixed

- **Rich-rendering work stranded in an isolated runtime clone is now part of the real release history.** The six reviewed commits were recovered onto current `main`, preserving Forge's newer URL-safety policy, and the delivery lane now has an explicit reopen path for prematurely accepted Goals.

## [2026-07-13] — v0.9.0 · Context-aware plans & issue archive

### Added
Expand Down
120 changes: 120 additions & 0 deletions DEVLOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,59 @@

> Append-only session log. Read at session start. Update at session end.

## 2026-07-13 — Rich-rendering recovery + human delivery acceptance

Recovered the six AXI-95–99 rich-rendering commits from the stale Codex bridge
clone onto current production `main`, resolving conflicts against the newer
issue context and URL-safety work. Issue descriptions, comments, and Focus now
share the rich renderer; direct media and allowlisted provider links get
bounded, accessible preview controls with inert fallbacks for unsafe schemes.

Closed the lifecycle defect that let successful agent reviews certify their
own delivery. All-DONE steps now complete the Plan while the Goal remains
ACTIVE with `OUTCOME_REVIEW` health. A signed-in operator must explicitly
accept a non-empty outcome summary plus durable delivery evidence; premature
Goals can be reopened with an audited reason. Added migration 0099 for the
structured evidence record. Agents intentionally cannot accept/reopen Goals
over MCP.

Made Plan collaboration visible instead of burying a generic composer under
each step. Step rows now expose **Ask @agent**, prefill the assigned agent,
focus the shared mention-aware composer, and retain ordinary comments for
context that should not dispatch work. Goal outcome review links directly to
the final step discussion.

Verification for the v0.10.0 release: `pnpm lint` (existing repository
warnings only), `pnpm typecheck`, the full Vitest suite (**1,159 passed; 1
skipped**), `git diff --check`, a fresh Next.js production build, and the full
Playwright suite (**37 passed**).

## 2026-07-12 — AXI-97 rich issue rendering integration

Integrated the shared rich body renderer into the remaining issue-adjacent
description surface. The main issue detail description and comment timeline
already render through `RichContentRenderer`; the fullscreen focus issue view
now uses the same renderer instead of raw `whitespace-pre-wrap` text, so image
URLs, video URLs, normal links, provider embeds, and Forge attachment/link
tokens preview consistently without changing stored issue description data or
the existing edit/save flows.

Verification: `corepack pnpm lint` passed and `corepack pnpm typecheck` passed.
DB-backed tests were not run in this bridge container because it has no
Postgres/Redis/MinIO/Docker services.

## 2026-07-11 — AXI-95 rich preview rendering contract

Defined the shared rich preview contract for chat/message markdown surfaces.
`docs/agents/chat.md` now specifies inline image, video, file, LINK attachment,
`forge-link`, normal URL, and allowlisted provider embed behavior; max preview
sizing; collapsed/expanded/hidden states; per-preview actions; and safe
fallback/error behavior. `docs/guide/time-and-attachments.md` now links
attachment readers back to that shared contract.

Verification: documentation diff reviewed. `corepack pnpm lint` and
`corepack pnpm typecheck` were run in the bridge container.

## 2026-07-13 — Plan context integrity + reversible issue archive

Closed the execution-context gaps that let materialized plan issues look like
Expand Down Expand Up @@ -12281,3 +12334,70 @@ Verification: lint and typecheck passed; 1,126 unit/integration tests passed
(one live-only test skipped); and a forced fresh production build plus all 37
Playwright tests passed. This change is local only; production was inspected
read-only and was not deployed or mutated.
Verification: `corepack pnpm lint` clean; `corepack pnpm typecheck` pass;
`git diff --check` clean. DB-backed tests were not run because this
codex-bridge container has no Postgres/Redis service stack.

---

## 2026-07-11 — AXI-96 rich issue content renderer

Extended the shared safe markdown renderer used by issue descriptions and
comments into an explicit `RichContentRenderer` export while keeping the
existing attachment-aware renderer API compatible for other surfaces.

The renderer now detects direct image and browser-playable video URLs in issue
content, keeps the original URL clickable/readable, and renders bounded inline
previews. Generated media/provider previews have a compact Slack-style action
menu for collapse, open, and hide/show controls, using existing tokens and
density-aware text utilities.

Verification: `corepack pnpm lint` clean; `corepack pnpm typecheck` pass.
DB-backed tests were not run because this codex-bridge container has no
Postgres/Redis service stack.

---

## 2026-07-12 — AXI-98 rich rendering behavior tests

Added focused rich-rendering regression coverage for plain text, multiple
inline links, direct image/video previews, YouTube embed promotion, unsupported
links, malformed URLs, preview hide/collapse state transitions, and issue-detail
usage of `RichContentRenderer`.

Extracted the preview action state into a tiny reducer used by the existing
preview controls so hide/collapse/show behavior can be tested without adding a
browser-only test dependency.

Verification: `corepack pnpm lint` clean; `corepack pnpm typecheck` pass;
`node_modules/.bin/vitest run tests/unit/rich-rendering.test.ts` pass (7).
`corepack pnpm test` was attempted and reached the normal command, but this
codex-bridge container has no `DATABASE_URL`/Postgres service, so Prisma-backed
router/service tests failed during fixture setup.

---

## 2026-07-12 — AXI-99 rich rendering accessibility/security review

Reviewed the rich issue content renderer for XSS safety, keyboard/screen-reader
accessibility, mobile preview behavior, visual token usage, and many-preview
performance. Fixed two review blockers before approval: markdown links with
scriptable/non-approved schemes now render as plain text instead of anchors, and
preview action dropdown controls now expose explicit screen-reader labels plus
Escape handling.

Added regression coverage for scriptable markdown link handling and preview
action labels alongside the existing rich-rendering behavior tests.

Verification: `pnpm test tests/unit/rich-rendering.test.ts` pass (9);
`pnpm lint` clean; `pnpm typecheck` pass; `git diff --check` clean.

Follow-up review pass: tightened provider preview polish by adding explicit
screen-reader labels to YouTube, GitHub, Loom, and Figma open controls, and
made the compact GitHub preview metadata wrap cleanly on narrow layouts.

Added regression coverage for provider preview action labels and GitHub card
responsive constraints.

Verification: `pnpm test tests/unit/rich-rendering.test.ts` pass (10);
`pnpm lint` clean; `pnpm typecheck` pass; `git diff --check` clean.
68 changes: 68 additions & 0 deletions docs/agents/chat.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,74 @@ bold/italic, inline code, fenced code blocks (with copy buttons), blockquotes,
unordered lists, attachments, tool-call cards, and local SYSTEM bubbles from
slash commands.

### Rich previews contract

Chat, comments, descriptions, notes, and artifact bodies use one rendering
contract for inline media and links. The renderer is intentionally allowlist-
driven: Forge embeds only known-safe media surfaces and never executes remote
HTML or scripts from a message body.

| Input | Default rendering | Expanded rendering | Plain-link fallback |
| --- | --- | --- | --- |
| Uploaded image attachment (`image/png`, `image/jpeg`, `image/gif`, `image/webp`, `image/svg+xml`) | Inline thumbnail when rendered from an image token or attachment list. | Attachment lightbox with fit-to-viewport preview. | File chip if the presigned URL, image decode, or storage lookup fails. |
| Uploaded video attachment (`video/mp4`, `video/webm`, `video/quicktime`) | Compact file chip in dense message bodies; canvas/attachment preview surfaces may show an inline player. | Attachment lightbox or preview card with native controls and no autoplay. | File chip with open/download actions if playback or presign fails. |
| Uploaded non-media file | File chip with MIME-aware icon, filename, and size. | Attachment lightbox preview when Forge has a safe renderer; otherwise open/download. | File chip remains the canonical view. |
| LINK attachment | Link chip with favicon or external-link icon, title/hostname, and external indicator. | Opens the canonical URL in a new tab. | Hostname chip if title or favicon lookup fails. |
| `forge-link:https://...` markdown token | Inline link chip matching LINK attachment styling. | Opens in a new tab. | Plain text if the scheme is not `http` or `https`. |
| Normal markdown link or bare `http(s)` URL | Standard text link. | Opens in a new tab. | Standard text link; no rich card is fetched automatically. |
| Allowlisted product embed URL | Provider embed card for known safe providers only, currently Forge artifacts plus YouTube, GitHub, Loom, and Figma. | Embedded card/player in the body, constrained to the preview size rules below. | Standard text link when provider detection fails or the provider cannot render safely. |

Preview sizing is capped by surface:

- Inline image thumbnails are square, approximately 80 px, object-fit cover.
- Message/body embed cards use the available body width and should cap at
640 px wide and 360 px tall, preserving media aspect ratio.
- Attachment lightbox previews fit within the modal viewport and never force
page scroll outside the modal.
- Canvas preview cards use the node bounds; new preview cards default to a
larger card height so the preview is useful, then resize with the canvas
node.
- No preview should expand a chat bubble, comment, or note beyond the readable
column width. Long filenames, titles, and URLs truncate in the middle or end
instead of reflowing controls.

Collapsed and hidden states:

- Dense message bodies default to compact chips for non-image files and links.
- Each preview-capable attachment or embed has a collapsed state: chip/card
summary with filename or title, host/MIME/size metadata, and an expand action.
- Expanded previews show the media/embed in place when the surface supports
inline expansion; otherwise they open the attachment lightbox.
- Users can collapse an expanded inline preview back to the chip/card summary.
- A dismissed preview hides only that preview instance for the current surface;
it does not delete the attachment, mutate message markdown, or hide the same
attachment everywhere else.

Per-preview actions:

- File previews: open in new tab, download, copy short-lived presigned URL,
and delete when the current user has permission for that target.
- LINK and `forge-link` previews: open in new tab and copy canonical URL.
They do not expose download because Forge has no bytes for them.
- Embed previews: open source in new tab, copy URL, collapse, and hide preview.
- Destructive actions use the existing confirmation flow and update the
surrounding attachment list after success.

Fallback and error behavior:

- Presign, fetch, decode, provider-detection, favicon, and playback failures
must degrade to a chip or standard link; they must not leave broken image,
iframe, or video chrome in the message.
- Unsupported MIME types should already be rejected at upload. If older data or
bad metadata reaches the renderer, render a generic file chip.
- External HTML is never injected into the DOM. Provider embeds are implemented
with first-party components or sandboxed, allowlisted iframe URLs; unknown
URLs remain normal links.
- Remote media does not autoplay. Video controls are user-initiated, and audio
stays muted/off until the user starts playback.
- Copying a presigned file URL should label the result as short-lived because
Forge download URLs expire.

## Status and diagnostics

The right-hand Chat status rail is the operator-facing source of truth for a
Expand Down
34 changes: 25 additions & 9 deletions docs/concepts/orchestration.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,11 @@ DAG, AgentCrew, ContextSet, ReviewGate, ActionRequest). It adds the

## How a goal runs

A **goal** is an automated loop that runs to completion — not a static
checklist you tick off by hand. You state the objective, approve the plan,
and the crew drives it through to "achieved" on its own, within the budget
and time caps you set.
A **goal** is an automated execution loop with a human delivery boundary — not
a static checklist you tick off by hand. You state the objective, approve the
plan, and the crew drives every step through review within the budget and time
caps you set. Forge completes the Plan automatically; an operator accepts the
delivered outcome before the Goal becomes achieved.

1. **Objective** — You state a high-level goal and (optionally) assign a
crew to run it.
Expand All @@ -45,8 +46,11 @@ and time caps you set.
them in parallel.
5. **Review** — A reviewer judges each finished step. A pass advances the
plan; a fail sends it back with feedback to retry.
6. **Achieved** — When every step passes, the goal completes. Budget and
time caps stop runaway loops automatically.
6. **Accept outcome** — When every step passes, the Plan completes and the Goal
remains active in `OUTCOME_REVIEW`. An operator records what shipped plus at
least one durable proof (PR, commit, deployment, test, artifact, or other
reference). Only that explicit acceptance marks the Goal achieved. Budget
and time caps stop runaway loops automatically.

### Use cases

Expand Down Expand Up @@ -103,6 +107,12 @@ evidence. An operator's explicit `DONE` or `CANCELED` Issue transition is
authoritative in the other direction: Forge updates the one unambiguous linked
step, cascading dependents on Done or blocking the plan on Cancel.

Every Plan step also has an issue-like discussion thread. Use **Ask @agent**
or type `@profileKey` in the step composer to add context, ask a question, or
request follow-up without changing the step status. The mention materializes
issue-backed work when needed and wakes the named agent with the Goal, Plan,
Step, dependency, and operator-comment context attached.

## The loop

```
Expand Down Expand Up @@ -148,10 +158,15 @@ step, cascading dependents on Done or blocking the plan on Cancel.
│ │
└────────────────────────────────────────────────────┘
│
│ (every step DONE)
│ (every step DONE: execution complete)
▼
┌────────────────┐ plan → COMPLETED; goal stays ACTIVE
│ OUTCOME_REVIEW │ operator records summary + delivery evidence
└───────┬────────┘
│ goal.acceptOutcome (UI-only human acceptance)
▼
┌──────────┐
│ ACHIEVED │ plan → COMPLETED, goal → ACHIEVED, achievedAt
│ ACHIEVED │ goal → ACHIEVED, achievedAt
└──────────┘
```

Expand Down Expand Up @@ -272,7 +287,8 @@ plans.recordVerdict({ stepId, verdict: "PASS", feedback: "meets contract", score
# PASS → step DONE → cascade → dependents become READY → dispatch.
# FAIL → retry (READY + retryCount++ + lastFeedback) or BLOCKED + gate.

# When every step is DONE, the plan COMPLETEs and the goal is ACHIEVED.
# When every step is DONE, the plan completes and the goal waits for human
# outcome acceptance with a summary and delivery evidence.
```

Crew management (admin-scoped):
Expand Down
5 changes: 5 additions & 0 deletions docs/guide/time-and-attachments.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,11 @@ favicon (origin + `/favicon.ico`, with a Lucide `ExternalLink` fallback
on image-load error) and the hostname inline. Clicking opens the URL
in a new tab.

Preview behavior for images, videos, link chips, provider embeds,
collapsed states, per-preview actions, and safe fallbacks is defined in
[Chat rich previews](/agents/chat.html#rich-previews-contract). The same
contract applies anywhere Forge renders attachment or link previews.

### `forge-link` markdown token

Inside any rendered markdown body (issue descriptions, comments,
Expand Down
10 changes: 10 additions & 0 deletions docs/reference/mcp.md
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,13 @@ Scope: `READ_ISSUES` for reads, `WRITE_ISSUES` for the loop mutations,
| `goals.create` | `{ title, description?, issueId?, crewId?, maxTotalCostUsd?, maxWallTimeMinutes? }` → `{ id }`. Emits `GOAL_CREATED`. |
| `goals.abandon` | `{ id, reason? }` → terminal `ABANDONED`; cancels any active plan attempt. |

When every required step reaches `DONE`, Forge marks the active Plan
`COMPLETED` but keeps the Goal `ACTIVE` with operating health
`OUTCOME_REVIEW`. Agents can report results through comments, artifacts, and
`goals.update`, but cannot accept their own delivery. A signed-in operator must
record a non-empty outcome summary plus at least one durable evidence reference
in the Goal UI before it becomes `ACHIEVED`.

```json
// goals.create
{ "title": "Ship the importer", "crewId": "crew_…", "maxTotalCostUsd": 5 }
Expand Down Expand Up @@ -735,6 +742,9 @@ These surfaces are admin/UI only and not exposed to agents:
- **Dispatch analytics** — `analytics.dispatch.summary`,
`analytics.dispatch.timeseries`. Aggregate views over many agents'
activity, intentionally not part of an agent's self-service surface.
- **Goal outcome acceptance/reopen** — completing execution is not permission
to certify delivery. `goal.acceptOutcome` and `goal.reopen` are human UI/tRPC
actions and are intentionally absent from MCP.

If you have a use case that wants one of these on MCP, open an issue — the
gate is intentional but not absolute.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "forge",
"version": "0.9.0",
"version": "0.10.0",
"private": true,
"description": "Forge — a fast, minimalist, keyboard-driven project management platform with pluggable agents.",
"license": "MIT",
Expand Down
1 change: 1 addition & 0 deletions prisma/migrations/0099_goal_outcome_evidence/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE "Goal" ADD COLUMN "outcomeEvidence" JSONB;
5 changes: 5 additions & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -3078,6 +3078,11 @@ model Goal {
successCriteria String? @db.Text
/// Operator-facing closeout summary populated during or after delivery.
outcomeSummary String? @db.Text
/// Operator-accepted proof that the outcome was actually delivered. Shape:
/// array of `{ kind, label, url?, ref? }` entries (PR, commit, deployment,
/// test, artifact, or other). A completed plan remains ACTIVE until a human
/// accepts a non-empty summary and at least one evidence entry.
outcomeEvidence Json?
/// Optional outcome horizon; plans retain their own execution budgets.
targetDate DateTime?
status GoalStatus @default(OPEN)
Expand Down
Loading
Loading