Skip to content

cy-create-tasks can write an unquoted title containing a colon, and the spec-cycle importer then rejects the whole task set #663

Closed

Description

@jillesmc

CompozyOS version

compozy 0.3.0-beta.27 (commit 7b62a7cd1)

Still present on the latest release. git log --oneline v0.3.0-beta.25..v0.3.0-beta.27 -- extensions/spec-cycle/ returns no commits, and the template still writes the field unquoted.

Operating system

Linux (x86_64)

Area

Core / daemon, Extensions

ACP agent

Claude Code via ACP

Model / provider

claude-opus-5. Not model-specific: the defect is in the file the skill writes.

Steps to reproduce

Context, since this arrives without one. I have been running a structured comparison of
agent-orchestration tools, and CompozyOS is one of them. This came out of an experiment where the
same task is planned twice and implemented by the same Loop both times. One arm stopped producing
any implementation at all, and this is why.

  1. Ask a session to plan a feature whose natural task title contains a colon. Mine came out of
    cy-create-spec plus cy-create-tasks with no special prompting:

    Use the cy-create-spec skill and then cy-create-tasks to plan the work below
    under the slug 'logsum'.
    
  2. cy-create-tasks writes .compozy/tasks/logsum/task_01.md with this frontmatter:

    ---
    status: pending
    title: Resumo de log: nucleo e CLI (fatia 1 / MVP)
    type: feature
    complexity: medium
    ---
  3. Run the Loop that consumes it:

    compozy loop run --name implement-tasks --input slug=logsum

What happened, and what did you expect?

The task set cannot be imported, and the Loop never implements anything.

daemon: execute loop action run
  task_id = loop.looprun-9e062214c7feff4d.g2.node.load_tasks.0
  error   = call action tool "ext__spec_cycle__import_tasks":
            The task set for .compozy/tasks/logsum/task_*.md could not be imported.

The underlying parser error:

loop: validation failed: parse md_tasks task file "task_01.md":
yaml: line 2: mapping values are not allowed in this context

title: Resumo de log: nucleo e CLI is an unquoted YAML scalar containing : , which opens a
nested mapping. The value is not representable this way, so yaml.Unmarshal fails and the whole
directory is rejected.

So cy-create-tasks writes a file that the spec-cycle importer cannot read. The two halves of
the same bundled extension disagree about the format.

Minimal reproduction, with a negative control

I ran the real importer (importMarkdownTasks) against two directories that differ in one
character pair:

task_01.md frontmatter importMarkdownTasks
title: Resumo de log: nucleo e CLI fails: yaml: line 2: mapping values are not allowed in this context
title: "Resumo de log: nucleo e CLI" imports with no error

Same manifest, same node ids, same everything else. Quoting is the entire difference.

How often it fires, measured rather than assumed

This is intermittent, not systematic, and I want to be precise about it because I got it wrong
in my own notes first.

It fires only when the title the agent chooses happens to contain : . I have since run two more
pre-registered experiments on this path, 14 rounds in total, each one invoking cy-create-spec
plus cy-create-tasks. It did not fire in any of them. Across those rounds the generated
titles were ordinary and colon-free, for example Tolerancia a log fora do formato and
Ranking de repeticao e --top.

So: a maintainer running this once may well not reproduce it. The minimal reproduction above,
with its negative control, is the reliable way to see it, and the template inspection is the
reason it can happen at all. I would not describe it as "the importer is broken"; I would describe
it as "the skill can emit a file the importer refuses, and nothing prevents it".

The experiments that produced this measurement, including the raw per-round records, are public
at https://github.com/jillesmc/spec-method-ab.

Why the skill produces it

extensions/spec-cycle/skills/cy-create-tasks/references/task-template.md shows the field
unquoted, on origin/main:

---
status: pending
title: [Task title]
type: [a standard work-type slug or an approved project-specific lowercase hyphenated slug]
complexity: [low, medium, high, critical]
---

Nothing in task-template.md or task-context-schema.md mentions quoting, colons, or YAML
escaping. I searched both for quote, colon, escape and yaml, and the only hits are
structural references to the schema.

The schema also requires that title match the first H1 of the body. A heading like
# Task 1: Resumo de log: nucleo e CLI is completely ordinary prose, so the colon is not an
unusual input. In my runs it appeared on the first attempt, without me steering toward it.

The second-order effect, which may deserve its own issue

When the import fails, the Loop run does not reach a terminal state. Twenty-five minutes
later:

status            = running
completion_state  = complete
generation        = 2
tokens_used       = 0
started_at        = 2026-09-15T16:46:12.703Z
last_progress_at  = 2026-09-15T16:46:12.916Z

last_progress_at is 213 ms after started_at and never advances. The run is not in any of the
six terminal states, so nothing settles it, and concurrency: forbid means the next
implement-tasks start on that workspace is refused with active_loop_run_exists. An operator
waiting on the run waits forever.

I am reporting this as one issue because the second symptom is reached only through the first,
but they look independent to me: a load-time action failure should still produce failed, whatever
caused it. Happy to split it if you prefer.

What I expected

cy-create-tasks and the spec-cycle importer should agree on the file format. Any of these
would close it:

1 - Quote the value when it needs quoting. The skill owns the write, so the smallest fix is in
the template plus a line in the schema reference saying scalars containing : must be quoted.

2 - Or make the importer tolerant. Parse the frontmatter leniently for the four scalar fields,
since status, title, type and complexity are all plain strings and none of them is ever a
nested mapping.

3 - And settle the run either way. An action that fails at load should drive the run to
failed, so the operator sees a stopped run instead of one that reports running with zero
tokens forever.

I would pick 1 and 3. Option 2 alone would leave other YAML metacharacters in the same trap.

What I did not verify

I did not check which other generated files have the same exposure. _tasks.md carries a
workflow key and a display table, and SOUL.md and AGENT.md have their own strict
frontmatter. I only proved this path, with the importer, for task_NN.md.

Logs

# the file as written by cy-create-tasks, unmodified
$ sed -n '1,6p' .compozy/tasks/logsum/task_01.md
---
status: pending
title: Resumo de log: nucleo e CLI (fatia 1 / MVP)
type: feature
complexity: medium
---

# the manifest is fine; only the task file fails
$ sed -n '1,8p' .compozy/tasks/logsum/_tasks.md
---
schema_version: "compozy.tasks/v2"
workflow: logsum
graph:
  nodes:
    - id: task_01
      file: task_01.md

# still unquoted on the latest code
$ git show origin/main:extensions/spec-cycle/skills/cy-create-tasks/references/task-template.md | sed -n '10p'
title: [Task title]

# and the importer still unmarshals straight into the struct
$ git show origin/main:extensions/spec-cycle/import_tasks_parser.go | grep -n 'yaml.Unmarshal'
	if err := yaml.Unmarshal(parts.Metadata, &meta); err != nil {

Duplicate search performed (title and body, open and closed, is:issue): import_tasks ·
task frontmatter · mapping values are not allowed · cy-create-tasks · compozy.tasks/v2 ·
yaml frontmatter. No hits.

Final checks

  • I searched existing issues and this is not a duplicate.
  • I can reproduce this on the latest release.

Activity

  1. jillesmc commented on Sep 21, 2026

    @jillesmc
    Author

    Context for this defect, including the experiments where I measured how often it fires: #664

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions