Skip to content

release: v0.1.7 (gate/tournament fixes + Google Search Console verification + SEO content)#55

Merged
heggria merged 17 commits into
mainfrom
release/0.1.7
Jul 8, 2026
Merged

release: v0.1.7 (gate/tournament fixes + Google Search Console verification + SEO content)#55
heggria merged 17 commits into
mainfrom
release/0.1.7

Conversation

@heggria

@heggria heggria commented Jul 8, 2026

Copy link
Copy Markdown
Owner

Checklist

  • I read CONTRIBUTING.md.
  • pnpm run typecheck passes.
  • pnpm test passes.
  • Website builds clean (TASKFLOW_BASE_PATH=/taskflow npm run build, 105 pages).
  • One concern per PR — intentionally bundled: this ships the v0.1.7 release prep and the SEO work that depends on reaching main to deploy (see below).

Related issue

Unblocks Google Search Console ownership verification — the verification meta tag currently only exists on this branch, not main, so the live site cannot be verified until this merges and deploy-website runs.

What changed

This PR lands the full v0.1.7 branch. Two logical groups:

1. v0.1.7 release prep + fixes

  • chore(release): prepare v0.1.7
  • refactor(mcp-core): rename taskflow-mcp → taskflow-mcp-core
  • fix(pi-taskflow): make built-in agents upgrade hint truly one-time
  • fix(core): surface parse errors with position in file loaders
  • fix(flowir): close three provenance/round-trip gaps
  • fix(gate): parse Markdown verdicts, fail closed, enforce output format
  • fix(tournament,score): extend marker tolerance to WINNER/SCORE

2. SEO — Google Search Console + on-page fixes + new content

Technical (so the live site can be verified & ranked):

  • Wire the GSC verification code (iBm6KBJ…) as a hardcoded default — CI never set GOOGLE_SITE_VERIFICATION, so the meta tag was absent in production.
  • Enrich the root redirect page: was a bare <title>taskflow</title> shell with no description/og/canonical → now full SEO meta + verification tag, canonical → /en/.
  • Strengthen the homepage <title> from taskflowtaskflow — Declarative DAG Orchestration for Coding Agents (title is the feat: make built-in agents configurable via /tf init #1 on-page factor); split out a brand field so subpages keep the short X | taskflow template.
  • Add missing homepage to taskflow-hosts/package.json.

New content (long-tail, high-intent — the unwinnable generic "taskflow" keyword strategy):

  • Comparisons (comparisons/): taskflow vs imperative workflows, vs built-in subagents, vs LangGraph — these X vs Y queries have high intent and low competition.
  • Blog (blog/): orchestrate Codex subagents, Claude Code + MCP workflow, what-is-a-task-graph.
  • Bilingual (full EN + zh-CN mirrors). +16 URLs (sitemap 81 → 97). Each page inherits full SEO automatically: descriptive title, description, canonical, hreflang, TechArticle + Breadcrumb JSON-LD.

Also done via gh (already live, not in this diff): repo homepageUrl, description (all 4 hosts), topics (+claude-code, +opencode, +mcp).

After merge

  1. deploy-website runs → live site gets the verification tag.
  2. @heggria verifies ownership in Google Search Console (HTML-tag method).
  3. Submit sitemap https://heggria.github.io/taskflow/sitemap.xml.

Screenshots / TUI output

N/A (docs site only).

heggria added 17 commits July 7, 2026 11:05
The npm names `taskflow-mcp` and `taskflow-mcp-server` were squatted by
an unrelated package, so the host-neutral MCP server ships as
`taskflow-mcp-core`. Syncs the directory rename across dependency pins,
workspace config, publish workflow, host adapters, and docs; fixes two
stale references in CONTRIBUTING.md and the library RFC. Adapter bin
names (codex-taskflow-mcp / claude-taskflow-mcp / opencode-taskflow-mcp)
are unchanged.

Part of the v0.1.6 release.
The session_start "built-in agents are no longer synced to .pi/agents/"
hint claimed to be a one-time upgrade hint but had no persistence — it
re-printed on every session as long as settings.json lacked a taskflow
key and the project had .pi/agents/*.md.

Track shown-state with a marker file (~/.pi/agent/.taskflow-upgrade-hint-shown),
created atomically (flag "wx") right after the first print. Subsequent
sessions skip the print. Best-effort: an unwritable agent dir only means
the hint may show once more; it never blocks session startup.
…ixed

The ba0249d change (marker file so the "built-in agents are no longer
synced" hint stops repeating every session) ships with the 0.1.7 release
branch and is now noted in the changelog under a new [0.1.7] section.
…eview

A multi-agent review of the 0.2.0 DSL RFC (run review-020-design)
cross-checked the FlowIR seam against PhaseSchema and found three
correctness bugs in the *current* engine — independent of the DSL, but
the DSL design made them load-bearing. All three affect cache/provenance
soundness or JSON↔DSL round-trip fidelity.

1. SIDECAR_PHASE_FIELDS omitted 8 Phase fields (agent, run, input,
   timeout, expect, reflexion, idempotent, score). A JSON→FlowIR→JSON
   round-trip silently dropped them, leaving script/gate/loop phases
   unrunnable. Added them + a structural round-trip test that asserts
   every author field survives the projection (so a future omission
   fails loudly, not silently).

2. collectRefs did not scan `run` (array form), `input` (script stdin),
   or `def` (inline sub-flow string form) — all three support {steps.X}
   interpolation at runtime, so their references never entered the
   declared dependency graph. recompute could skip a phase whose stdin
   or argv genuinely depended on a now-stale upstream. Added scanning +
   per-field tests.

3. translateTaskflow built declaredDeps.reads from interpolation refs
   only; a phase's explicit `dependsOn` (a semantic ordering no
   interpolation captures — e.g. sequential scripts sharing the
   filesystem) was dropped from RunState.declaredDeps. Now merged
   (observed ∪ declared), with a regression test.

1144/1144 tests pass (4 new). The new sidecar test is reverse-verified:
removing any covered field fails it.
Four user-facing file loaders (readDefineFile, readFlowFile/listFlows,
tryReadRunFile, readMeta/readMetaNextTo) collapsed two distinct failures —
file missing vs file malformed — into a single null / "X not found or
unparseable" result. The underlying JSON.parse SyntaxError (byte offset +
line/column) was swallowed by the lenient safeParse and never reached the
user, so a hand-authored defineFile with a stray bare newline reported
"defineFile not found or unparseable" and sent authors chasing a phantom
path/cwd problem.

Loaders now return a discriminated LoadResult<T> with reason "missing" |
"unparseable" and a detail field carrying the original parse error. A shared
describeLoadFailure(r, what) formats the user-facing message. New strict
parseStrict(text, { allowFence }) in interpolate.ts preserves the SyntaxError;
safeParse is unchanged so all ~25 LLM/subagent output paths keep their
fail-open recovery. listFlows now warns on a corrupt saved flow instead of
silently dropping it; new getFlowDiagnosed / loadRunDiagnosed distinguish
corrupt-vs-missing for by-name / by-runId resolution.

Breaking (pre-1.0): readDefineFile, readMeta, readMetaNextTo return
LoadResult<T> instead of T | null. The intentionally fail-open paths
(index-rebuild scans, cache.ts file hashing, path-traversal rejections)
are unchanged.

1392 tests pass (core 1146 + adapters 246); typecheck clean.
Bump all seven packages + internal dependency pins (taskflow-core /
taskflow-hosts / taskflow-mcp-core) + plugin manifests (.mcp.json /
.codex-plugin / .claude-plugin / opencode.json) + README/README.zh-CN
version notes + SECURITY.md + RELEASE.md tag example to 0.1.7, and
regenerate pnpm-lock.yaml.

Pre-flight green: typecheck clean, 1146/1146 core tests pass, all seven
packages build (dist) at 0.1.7.
#54)

A genuine BLOCK was silently downgraded to PASS when models wrapped the
verdict token in Markdown emphasis (VERDICT: **BLOCK**). The bare-token
regex missed it and the miss fell into the fail-open default, so a blocked
review could continue downstream unchecked.

Three layered fixes:

1. Parser tolerance — a shared VERDICT_TOKEN_RE (scorers.ts) now tolerates
   `*`/`_`/`` `/`~` emphasis runs on either side of the verdict word. Used
   by both parseGateVerdict and parseJudgeOutput, replacing two identical
   bare-token regexes.

2. Fail-closed default — gate *model output* that cannot be parsed now
   BLOCKS instead of passing. A gate that cannot reach a verdict cannot be
   trusted to pass; halting is recoverable (prior phases persist, run is
   resumable). Config slips (unresolved score.target, malformed scorers)
   stay fail-open with a warning — they are authoring errors, not a judge
   that couldn't decide. An explicit non-blocking JSON verdict
   ({"verdict":"No issues found"}) is a semantic PASS, not ambiguity.

3. Auto-appended format suffix — a free-text gate whose task omits a
   VERDICT: instruction now gets the exact terminator auto-appended, so a
   model never "forgets" to emit one. Applied at all four gate-task
   construction sites including the onBlock:retry loop (previously missed).
   Skipped for gates with an output:"json" + expect contract.

For maximum robustness, prefer output:"json" + expect enum
({verdict:{enum:["pass","block"]}}) which machine-validates the verdict.

Breaking (pre-1.0): a gate whose model output has no parseable verdict now
blocks instead of silently passing. Migration: emit VERDICT: PASS|BLOCK
(auto-appended if omitted), adopt the JSON+expect contract, or mark the
gate optional:true with a downstream fallback.

Tests: 1148 pass (added Markdown-emphasis regression cases for both
parseGateVerdict and parseJudgeOutput, the fail-closed default, and the
auto-append behavior; updated the two fail-open tests to fail-closed).
Docs: AGENTS.md invariant #4 + Error Handling, README, CHANGELOG, and the
shared skill sources (regenerated for all four hosts).

Closes #54.
- Wire the GSC verification code (iBm6KBJ...) as the hardcoded default in
  [lang]/layout.tsx so the meta tag emits in every build (CI never set the
  GOOGLE_SITE_VERIFICATION env var, so the tag was absent in production).
- Enrich the root redirect page (app/page.tsx): was a bare <title>taskflow</title>
  shell with no description/og/canonical; now has full SEO meta + the
  verification tag, with canonical -> /en/.
- Strengthen the homepage <title> from 'taskflow' to the keyword-rich
  'taskflow — Declarative DAG Orchestration for Coding Agents' (title is the
  #1 on-page SEO factor); split out a  field so subpages keep the short
  'X | taskflow' template.
- Add the missing  field to taskflow-hosts/package.json so the npm
  page links back to the docs.

Also updated via gh CLI: repo homepageUrl, description (mention all 4 hosts),
and topics (+claude-code, +opencode, +mcp).
Long-tail, high-intent content pages that capture search traffic where
taskflow is the best answer (the generic 'taskflow' keyword is unwinnable
against Apache Airflow's TaskFlow API). All pages reuse the existing docs
route, so each inherits full SEO automatically: descriptive title,
description, canonical, hreflang alternates, and TechArticle + Breadcrumb
JSON-LD.

Comparisons (the 'X vs Y' queries, very high intent):
- comparisons/index              — overview + one-axis mental model
- comparisons/taskflow-vs-workflow    — declarative DAG vs imperative code-mode
- comparisons/taskflow-vs-subagents   — vs built-in task/tasks/chain shorthand
- comparisons/taskflow-vs-langgraph   — vs the general-purpose graph framework

Blog (long-tail how-to / concept queries):
- blog/index                          — listing
- blog/orchestrate-codex-subagents    — 'how to orchestrate codex subagents'
- blog/claude-code-mcp-workflow       — 'claude code mcp workflow' w/ gates
- blog/what-is-a-task-graph           — 'task graph DAG LLM' concept piece

Bilingual: full EN + zh-CN mirrors. Adds 16 URLs (sitemap 81 -> 97).
Registered in both root meta.json sidebars under new sections.
The Markdown-emphasis blind spot from #54 was not unique to VERDICT — the
same bare-token regex pattern silently lost genuine signals in two more
decision parsers:

- parseTournamentWinner: `WINNER: **3**` missed the emphasis → silently
  reverted to variant 1, losing the judge's actual pick.
- parseJudgeOutput SCORE marker: `SCORE: **0.8**` missed → score dropped.

Refactor: a shared `markerRe(label, value)` factory in scorers.ts now emits
all three emphasis-tolerant regexes (VERDICT_TOKEN_RE, SCORE_TOKEN_RE,
WINNER_TOKEN_RE), tolerating `*`/`_`/`/`~` runs on either side of the
captured value. parseTournamentWinner and the SCORE parse adopt it; VERDICT
is rebuilt from the same factory for consistency (single source of truth).

Fail stances are deliberate and now consistent with each marker's semantics:
gate verdict / judge output → fail-closed (BLOCK); tournament winner →
fail-open (variant 1, never lose work — the variants are already computed,
so blocking would be worse than picking a safe default).

Also promotes structured output as the documented default for ALL decision
phases (gate verdict, tournament winner, router branch, judge score): prefer
`output:"json"` + `expect` which machine-validates the decision and leaves
no formatting the model can get subtly wrong. Free-text markers remain as a
tolerant back-compat path. Skill sources + README + CHANGELOG updated and
regenerated for all four hosts.

Tests: 1149 pass. Added Markdown-emphasis regression cases for WINNER and
SCORE markers; runtime-verified the factory-built regexes (clamp + emphasis
+ fail-open all correct).

Refs #54.
# Conflicts:
#	README.md
#	README.zh-CN.md
#	packages/claude-taskflow/package.json
#	packages/codex-taskflow/package.json
#	packages/opencode-taskflow/package.json
#	packages/taskflow-mcp-core/package.json
#	pnpm-lock.yaml
PostCSS < 8.5.10 did not escape `</style>` when stringifying CSS ASTs — an
XSS vector when user-submitted CSS is parsed and re-embedded in HTML
<style> tags (GHSA-qx2m-qp2m-jg93 / CVE-2026-41305, medium).

next@16.2.10 (a website/ transitive dep) pinned the vulnerable
postcss@8.4.31. A root pnpm.overrides now forces postcss@^8.5.10
workspace-wide, hoisting the single 8.4.31 resolution to 8.5.16 (the
version @tailwindcss/postcss already resolved). The website build (Next.js +
Tailwind CSS pipeline) was verified unaffected (105/105 pages).

Engine tests unaffected (1149 pass). Closes dependabot alert #5.
…viewport

- Root redirect page referenced /opengraph-image, which 404s (the OG image
  route is app/[lang]/opengraph-image.tsx → only /en/opengraph-image and
  /zh-cn/opengraph-image exist). Point og:image + twitter:image at
  /en/opengraph-image so social cards render.
- Move themeColor out of the metadata export into a generateViewport/viewport
  export (Next.js 15+ requires this; it was emitting a build warning on every
  docs page prerender).
Lands the trace-only slice of the deterministic-replay RFC (scoped to 0.1.7 by
a 3-reviewer cross-adversarial plan review: risk-reviewer + critic + reviewer
-> plan-arbiter; full replay logic defers to 0.2.0).

Foundation:
- trace.ts: TraceEvent schema (phase-start/end, subagent-call with resolved
  input + full output, decisions: gate-verdict / unreplayable), TraceSink
  interface, buffered FileTraceSink (per-phase buffer, one locked append at
  flush -> no lock contention on map/parallel fan-out), partial-line-tolerant
  readTrace, NoopTraceSink.
- replay.ts: ReplayDecision type contract (defined now so the trace schema and
  diff-report shape are fixed before events are emitted; replayRun() in 0.2.0).
- deterministic.ts: extract pure parseGateVerdict + a decoupled overBudget so a
  future replay imports them without the process-spawning runner.

Runtime:
- New optional RuntimeDeps.trace?: TraceSink — fail-open (missing/throwing sink
  never crashes a run) + host-agnostic (no host SDK in core). Runs with no sink
  behave identically to before.
- Instrument executePhase (phase-start/end), runOne (subagent-call on
  completion — the load-bearing record), gate verdict (decision), and emit an
  unreplayable marker for context-sharing / inner-flow / context-file /
  unobservable-deps phases (single-phase analog of hasUnobservedDependencies).
- store.ts: traceFilePath() + cleanup of .trace.jsonl + .trace.jsonl.lock in
  cleanupTerminalRuns (no unbounded disk accumulation).

Surface:
- pi: action=trace + /tf trace <runId> [--json]; wired trace into all 4
  RuntimeDeps construction sites (run + 2 recompute).
- MCP: taskflow_trace tool; also backfilled taskflow_why_stale +
  taskflow_recompute (dry-run only) — MCP previously lacked 5 analysis actions
  pi had. Wired trace into taskflow_run.

Tests: 8 new in trace.test.ts (no-op-sink invariant, capture emission, map
multi-emit, readTrace partial-line tolerance, FileTraceSink buffered round-trip
+ fail-open). Updated the 3 host adapters' tool-count assertions (8 -> 11).
1157 tests green; typecheck clean.
taskflow_trace / taskflow_why_stale / taskflow_recompute were added to the MCP
server (backfilled analysis actions). The comprehensive e2e hardcoded the
8-tool list; bump it to the 11-tool list. The basic e2e + claude/opencode e2e
use subset (includes) checks and were unaffected.
A deep cross-adversarial release-readiness review (scout -> risk/security/
quality reviewers -> critic cross-exam -> final-arbiter) returned
GO-WITH-CONDITIONS. This commit lands the P0 + P1 conditions:

P0 (ship-blockers):
- Bump stale @0.1.6 plugin pins in codex-taskflow/plugin/.mcp.json and
  claude-taskflow/plugin/.mcp.json to @0.1.7. Without this, codex/claude
  plugin users would get a server missing taskflow_trace, taskflow_why_stale,
  taskflow_recompute, taskflow_save, taskflow_search (the 0.1.7 features).
  (opencode was already at 0.1.7.)

P1 (release-quality):
- Teach the 'trace' action in the skills (actions table 13 -> 15 incl. trace +
  search) so agents can discover/invoke it; rebuild generated SKILL.md.
- Fix the README MCP tool list (said 6 tools; now lists all 11) + add
  /tf trace + /tf peek to the Pi command table.
- Add trace decision-event tests (gate-verdict, unreplayable marker) — the
  events a 0.2.0 replay consumes were previously untested.
- Update skills-build drift-guard (13 -> 15 actions).

Arbiter verdict on the disputed trace-default/.gitignore claims: the risk +
security reviewers made a deference-cascade error (both wrongly asserted trace
is off-by-default; it is on-by-default at all 4 injection sites, and
.pi/taskflows/ is already gitignored). Quality reviewer was correct; its
findings weighted higher. Residual risk accepted: no trace opt-out yet
(TASKFLOW_TRACE=0 planned for 0.1.8). Semver: ship as 0.1.7 (pre-1.0; the
breaking changes are low-blast-radius internal API + a bug-fix surfacing).

1159 tests green; typecheck clean.
@heggria heggria merged commit f52e049 into main Jul 8, 2026
6 checks passed
@heggria heggria deleted the release/0.1.7 branch July 8, 2026 09:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant