From 1ffb3b095d20d49eeca54f76e84d4f1c3e591f3b Mon Sep 17 00:00:00 2001 From: "Jose I. Paris" Date: Tue, 6 Oct 2026 13:18:48 +0200 Subject: [PATCH 1/5] spec: 004 Role of each spec source Refs #3531 Signed-off-by: Jose I. Paris --- docs/specs/004-spec-source-role.md | 134 +++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 docs/specs/004-spec-source-role.md diff --git a/docs/specs/004-spec-source-role.md b/docs/specs/004-spec-source-role.md new file mode 100644 index 000000000..fdb6de8ba --- /dev/null +++ b/docs/specs/004-spec-source-role.md @@ -0,0 +1,134 @@ +--- +owner: jiparis +ticket: https://github.com/chainloop-dev/chainloop/issues/3531 +prd: +--- + +# Spec 004: Role of each spec source + +## Summary +This spec changes the spec capture of [Spec 002](002-session-spec-capture.md) and [Spec 003](003-spec-capture-during-session.md). It does not replace them. Today each spec source has a kind: ticket, document, image, or text. The kind tells the format of a source, but not its purpose. With this change, the agent can also record a role for each source: `task`, `spec`, `plan`, or `reference`. The CLI stores the role in the session material and in the annotations of the spec material. A tool that shows the sources can then group them by purpose. + +## Problem +- A reader of the evidence cannot tell a spec from a background document. Both have the kind `document`. +- A reader cannot tell an approved plan from other text. Both have the kind `text`. +- A ticket can hold the task, and it can also be only background for the work. The kind `ticket` does not tell which. +- A tool that shows the spec sources must guess the purpose from the kind. The guess is wrong for some sources. +- An image or another binary file has no header, so the agent cannot record anything about it. + +## Goals and Non-Goals +- Goal: each spec source can carry its purpose, as the agent decides it. +- Goal: the evidence holds the role next to the kind, in the spec entry and in the material annotations. +- Goal: the agent can give a role to a binary file too. +- Goal: sessions without roles stay valid, and earlier consumers keep working. +- Non-goal: a change to the kinds, or to how the CLI finds the kind. +- Non-goal: rules in the CLI that guess a role. The agent decides the role, as it decides what a spec is (D-001 of Spec 002). +- Non-goal: a source address or other metadata for binary files. Only the role is new. +- Non-goal: a change to the reminder at each user turn of Spec 003. + +## Requirements + +### R-001: Role vocabulary +A spec source MAY have one role. The roles are: +- `task`: the item that states the work to do, for example the ticket that the session works on. +- `spec`: a document that defines what to build, for example requirements or a design. +- `plan`: a plan for the work that the user approved in the session. +- `reference`: supporting material, for example a screenshot, a mockup, an example, or a background document. + +### R-002: Role in the header +The header of a text spec file MAY hold a `role` field. The CLI MUST read it with no regard to letter case. + +### R-003: Role of a binary file +For an image or another binary file, the agent MAY write a companion file. Its name is the name of the binary file plus `.meta.yaml`. It holds a `role` field. The CLI MUST apply that role to the binary file. The CLI MUST NOT store the companion file as a spec material of its own. The CLI MUST ignore a companion file with no binary file next to it. +- Done when: the agent copies a screenshot and writes its companion file with `role: reference`. The push records one image material with the role `reference`, and no material for the companion file. + +### R-004: Role in the evidence +When a source has a role, the system MUST record it in the spec entry of the session material. It MUST also record it in a `chainloop.spec.role` annotation on the spec material. When a source has no role, the system MUST leave out both. + +### R-005: Missing or unknown role +A role that is missing, empty, or not in the vocabulary MUST give no role. The system MUST NOT guess a role from the kind. A bad role MUST NOT stop the push. +- Done when: a header with `role: design` pushes a spec material with no role annotation, and the push succeeds. + +### R-006: Capture instruction +The capture instruction at session start SHOULD ask the agent to set the role of each source, with one short line for each role. It SHOULD tell the agent how to give a role to a binary file. + +## Constraints +- The repository is public. The instruction text and the format are visible to all users. +- The change to the evidence is additive. A consumer that does not know the role MUST still read the spec entries and materials. +- Only known header fields reach the evidence. A new field does not open the header to other keys. +- The instruction at session start goes into the agent context. It must stay short. + +## Proposal +The user does nothing new. At session start, the capture instruction lists the four roles. The agent adds a role to the header of each text file that it writes: + +```markdown +--- +kind: ticket +uri: https://tracker.example.com/issue/ENG-1234 +role: task +--- + +# ENG-1234: Add an export button +... +``` + +For a binary file, the agent writes a companion file next to it, with the suffix `.meta.yaml`: + +```text +spec folder +├── ticket-eng-1234.md kind: ticket, role: task +├── design-proposal.md kind: document, role: spec +├── approved-plan.md kind: text, role: plan +├── export-mockup.png image, stored as it is +└── export-mockup.png.meta.yaml role: reference +``` + +At push time, the CLI reads the role as it reads the kind and the source address. It normalizes the value, and it drops a value that is not in the vocabulary. It applies the role of a companion file to its binary file, and it does not upload the companion file. The spec entry and the material annotations then hold the role: + +```json +"spec": [ + { "kind": "ticket", "role": "task", "uri": "https://tracker.example.com/issue/ENG-1234", + "digest": "sha256:e4c2...", "captured_at": "2026-10-06T10:12:03Z" }, + { "kind": "image", "role": "reference", + "digest": "sha256:c2a1...", "captured_at": "2026-10-06T10:31:40Z" } +] +``` + +```json +{ + "name": "export-mockup.png", + "annotations": { + "chainloop.material.name": "spec-fd4e67-export-mockup", + "chainloop.material.type": "EVIDENCE", + "chainloop.spec.session_id": "fd4e6754-3b26-4f54-9807-13c58465bb35", + "chainloop.spec.kind": "image", + "chainloop.spec.role": "reference" + } +} +``` + +A tool that shows the sources groups them by role when a source has one. For a source with no role, the tool uses its own rule from the kind. The evidence holds only what the agent stated. + +## Decision Record + +| ID | Decision | Choice | Why (and what we rejected) | Source | +|----|----------|--------|----------------------------|--------| +| D-001 | How to record the purpose | A role field next to the kind | The kind is the format and the role is the purpose. A ticket can be the task or only background. Rejected: more kinds, for example a `plan` kind (it mixes format and purpose, and a document can be a spec or a reference). | drafting | +| D-002 | Role values | `task`, `spec`, `plan`, `reference` | Four values cover the purposes that a reviewer looks for: what to do, what to build, how, and supporting material. Rejected: only `spec`, with no role for all other sources (a reader cannot tell a task from a reference). | drafting | +| D-003 | Role of a binary file | A companion header file that the agent writes | The agent decides the role for every source, also for an image. Rejected: the CLI sets `reference` for each image (a guess, and a mockup can be the spec). Rejected: no role for binary files. | drafting | +| D-004 | Missing or unknown role | No role in the evidence | The evidence holds only what the agent stated. Consumers can apply their own rule. Rejected: a default role from the kind (a guess looks like a fact in the evidence). | drafting | +| D-005 | Instruction strength | SHOULD, in the session-start instruction only | A role is useful but not necessary, and the reminder at each turn must stay short (Spec 003). Rejected: MUST, and the roles in the reminder at each turn (more tokens on each turn). | drafting | +| D-006 | Name of the companion file | The binary file name plus `.meta.yaml`, for example `export-mockup.png.meta.yaml` | The suffix tells that the file holds metadata, not a spec. Rejected: the binary file name plus `.md`, with a header and an empty body (a reader can take it for an empty spec). | drafting | +| D-007 | Companion file with no binary file | The CLI ignores it, with no warning | The file holds no spec content, so the push loses nothing. Rejected: a warning in the session material (noise for a case with no loss). | drafting | + +## Open Questions +None. + +## Risks + +| Risk | Mitigation | +|------|------------| +| The agent gives a wrong role, for example `spec` for a background document. | The role is the agent's statement, as the kind is. The kind and the content stay in the evidence, so a reviewer can check. | +| The agent does not set a role. | The role is optional (R-005). Consumers use their own rule from the kind. The share of sources with a role is measurable from the evidence. | +| The agent forgets the companion file for an image. | The image has no role, and consumers use their own rule. | +| A source has more than one purpose. For example, a ticket also holds the full spec. | The agent records the main purpose. The instruction says to pick the role that tells why the source is in the session. | From 04c25abb89a2be0d2a1fe09adccdacaa6a2dfe21 Mon Sep 17 00:00:00 2001 From: "Jose I. Paris" Date: Tue, 6 Oct 2026 14:02:11 +0200 Subject: [PATCH 2/5] spec: 004 add an optional title to each spec source Refs #3531 Signed-off-by: Jose I. Paris Chainloop-Trace-Sessions: d4043d7b-f121-41dd-a642-42aff4c66211 --- docs/specs/004-spec-source-role.md | 51 ++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/docs/specs/004-spec-source-role.md b/docs/specs/004-spec-source-role.md index fdb6de8ba..42098e74b 100644 --- a/docs/specs/004-spec-source-role.md +++ b/docs/specs/004-spec-source-role.md @@ -4,26 +4,27 @@ ticket: https://github.com/chainloop-dev/chainloop/issues/3531 prd: --- -# Spec 004: Role of each spec source +# Spec 004: Role and title of each spec source ## Summary -This spec changes the spec capture of [Spec 002](002-session-spec-capture.md) and [Spec 003](003-spec-capture-during-session.md). It does not replace them. Today each spec source has a kind: ticket, document, image, or text. The kind tells the format of a source, but not its purpose. With this change, the agent can also record a role for each source: `task`, `spec`, `plan`, or `reference`. The CLI stores the role in the session material and in the annotations of the spec material. A tool that shows the sources can then group them by purpose. +This spec changes the spec capture of [Spec 002](002-session-spec-capture.md) and [Spec 003](003-spec-capture-during-session.md). It does not replace them. Today each spec source has a kind: ticket, document, image, or text. The kind tells the format of a source, but not its purpose. A source also has no name that a person can read. With this change, the agent can also record a role and a title for each source. The role is `task`, `spec`, `plan`, or `reference`. The title is a short name, for example the title of a ticket. The CLI stores both in the session material and in the annotations of the spec material. A tool that shows the sources can then group them by purpose and label them by title. ## Problem - A reader of the evidence cannot tell a spec from a background document. Both have the kind `document`. - A reader cannot tell an approved plan from other text. Both have the kind `text`. - A ticket can hold the task, and it can also be only background for the work. The kind `ticket` does not tell which. - A tool that shows the spec sources must guess the purpose from the kind. The guess is wrong for some sources. +- A source has no name that a person can read. A tool must use the material name, which the CLI makes from the file name. The CLI shortens it and changes it to lower case, for example `ticket-eng-1234-comment-rca`. - An image or another binary file has no header, so the agent cannot record anything about it. ## Goals and Non-Goals -- Goal: each spec source can carry its purpose, as the agent decides it. -- Goal: the evidence holds the role next to the kind, in the spec entry and in the material annotations. -- Goal: the agent can give a role to a binary file too. -- Goal: sessions without roles stay valid, and earlier consumers keep working. +- Goal: each spec source can carry its purpose and a short title, as the agent decides them. +- Goal: the evidence holds the role and the title next to the kind, in the spec entry and in the material annotations. +- Goal: the agent can give a role and a title to a binary file too. +- Goal: sessions without roles or titles stay valid, and earlier consumers keep working. - Non-goal: a change to the kinds, or to how the CLI finds the kind. -- Non-goal: rules in the CLI that guess a role. The agent decides the role, as it decides what a spec is (D-001 of Spec 002). -- Non-goal: a source address or other metadata for binary files. Only the role is new. +- Non-goal: rules in the CLI that guess a role or a title. The agent decides them, as it decides what a spec is (D-001 of Spec 002). +- Non-goal: a source address or other metadata for binary files. Only the role and the title are new. - Non-goal: a change to the reminder at each user turn of Spec 003. ## Requirements @@ -39,7 +40,7 @@ A spec source MAY have one role. The roles are: The header of a text spec file MAY hold a `role` field. The CLI MUST read it with no regard to letter case. ### R-003: Role of a binary file -For an image or another binary file, the agent MAY write a companion file. Its name is the name of the binary file plus `.meta.yaml`. It holds a `role` field. The CLI MUST apply that role to the binary file. The CLI MUST NOT store the companion file as a spec material of its own. The CLI MUST ignore a companion file with no binary file next to it. +For an image or another binary file, the agent MAY write a companion file. Its name is the name of the binary file plus `.meta.yaml`. It holds a `role` field and a `title` field. The CLI MUST apply those values to the binary file. The CLI MUST NOT store the companion file as a spec material of its own. The CLI MUST ignore a companion file with no binary file next to it. - Done when: the agent copies a screenshot and writes its companion file with `role: reference`. The push records one image material with the role `reference`, and no material for the companion file. ### R-004: Role in the evidence @@ -50,22 +51,31 @@ A role that is missing, empty, or not in the vocabulary MUST give no role. The s - Done when: a header with `role: design` pushes a spec material with no role annotation, and the push succeeds. ### R-006: Capture instruction -The capture instruction at session start SHOULD ask the agent to set the role of each source, with one short line for each role. It SHOULD tell the agent how to give a role to a binary file. +The capture instruction at session start SHOULD ask the agent to set the role and the title of each source. It SHOULD give one short line for each role. It SHOULD tell the agent how to give a role and a title to a binary file. + +### R-007: Title +The header of a text spec file, and the companion file of a binary file, MAY hold a `title` field. When a source has a title, the system MUST record it in the spec entry of the session material. It MUST also record it in a `chainloop.spec.title` annotation on the spec material. When the title is missing or empty, the system MUST leave out both. The system MUST NOT make a title from the content or from the file name. +- Done when: a ticket file with `title: "ENG-1234: Add an export button"` pushes a spec entry and a material annotation with that title. + +### R-008: Title limits +The system MUST cut a title that is longer than 120 characters, and keep the first 120. The system MUST apply the secret redaction of Spec 002 to the title of a companion file before the title goes into the evidence. A bad title MUST NOT stop the push. ## Constraints - The repository is public. The instruction text and the format are visible to all users. -- The change to the evidence is additive. A consumer that does not know the role MUST still read the spec entries and materials. +- The change to the evidence is additive. A consumer that does not know the role or the title MUST still read the spec entries and materials. +- The title is text that an agent wrote. It can hold a secret, as the spec text can. - Only known header fields reach the evidence. A new field does not open the header to other keys. - The instruction at session start goes into the agent context. It must stay short. ## Proposal -The user does nothing new. At session start, the capture instruction lists the four roles. The agent adds a role to the header of each text file that it writes: +The user does nothing new. At session start, the capture instruction lists the four roles and asks for a short title. The agent adds a role and a title to the header of each text file that it writes: ```markdown --- kind: ticket uri: https://tracker.example.com/issue/ENG-1234 role: task +title: "ENG-1234: Add an export button" --- # ENG-1234: Add an export button @@ -81,15 +91,17 @@ spec folder ├── approved-plan.md kind: text, role: plan ├── export-mockup.png image, stored as it is └── export-mockup.png.meta.yaml role: reference + title: Export button mockup ``` -At push time, the CLI reads the role as it reads the kind and the source address. It normalizes the value, and it drops a value that is not in the vocabulary. It applies the role of a companion file to its binary file, and it does not upload the companion file. The spec entry and the material annotations then hold the role: +At push time, the CLI reads the role and the title as it reads the kind and the source address. It normalizes the role, and it drops a role that is not in the vocabulary. It cuts a long title. It applies the values of a companion file to its binary file, after it redacts the title, and it does not upload the companion file. The spec entry and the material annotations then hold the role and the title: ```json "spec": [ - { "kind": "ticket", "role": "task", "uri": "https://tracker.example.com/issue/ENG-1234", + { "kind": "ticket", "role": "task", "title": "ENG-1234: Add an export button", + "uri": "https://tracker.example.com/issue/ENG-1234", "digest": "sha256:e4c2...", "captured_at": "2026-10-06T10:12:03Z" }, - { "kind": "image", "role": "reference", + { "kind": "image", "role": "reference", "title": "Export button mockup", "digest": "sha256:c2a1...", "captured_at": "2026-10-06T10:31:40Z" } ] ``` @@ -102,12 +114,13 @@ At push time, the CLI reads the role as it reads the kind and the source address "chainloop.material.type": "EVIDENCE", "chainloop.spec.session_id": "fd4e6754-3b26-4f54-9807-13c58465bb35", "chainloop.spec.kind": "image", - "chainloop.spec.role": "reference" + "chainloop.spec.role": "reference", + "chainloop.spec.title": "Export button mockup" } } ``` -A tool that shows the sources groups them by role when a source has one. For a source with no role, the tool uses its own rule from the kind. The evidence holds only what the agent stated. +A tool that shows the sources groups them by role when a source has one, and labels them by title. For a source with no role, the tool uses its own rule from the kind. For a source with no title, it uses the material name. The evidence holds only what the agent stated. ## Decision Record @@ -120,6 +133,9 @@ A tool that shows the sources groups them by role when a source has one. For a s | D-005 | Instruction strength | SHOULD, in the session-start instruction only | A role is useful but not necessary, and the reminder at each turn must stay short (Spec 003). Rejected: MUST, and the roles in the reminder at each turn (more tokens on each turn). | drafting | | D-006 | Name of the companion file | The binary file name plus `.meta.yaml`, for example `export-mockup.png.meta.yaml` | The suffix tells that the file holds metadata, not a spec. Rejected: the binary file name plus `.md`, with a header and an empty body (a reader can take it for an empty spec). | drafting | | D-007 | Companion file with no binary file | The CLI ignores it, with no warning | The file holds no spec content, so the push loses nothing. Rejected: a warning in the session material (noise for a case with no loss). | drafting | +| D-008 | Name of a source | An optional title that the agent writes, next to the role | The agent knows the title of the source when it writes the file. The format already changes for the role, so a second field costs little. A tool can label a source from the session material alone. Rejected: the material name only (a short lower-case file stem). Rejected: a title that the CLI takes from the first heading (a guess that looks like a fact in the evidence). This changes the outcome of [#3528](https://github.com/chainloop-dev/chainloop/issues/3528), which closed a title field before the format had other changes. | drafting | +| D-009 | Where the title goes | The spec entry and a `chainloop.spec.title` annotation, as for the role | A tool that reads only one material can label it. Rejected: the spec entry only. | drafting | +| D-010 | Long title | Cut at 120 characters, and keep the first part | A model sometimes writes a full paragraph. A cut keeps a usable label. Rejected: drop a long title (the source loses its label). Rejected: no limit (long annotations and labels). | drafting | ## Open Questions None. @@ -131,4 +147,5 @@ None. | The agent gives a wrong role, for example `spec` for a background document. | The role is the agent's statement, as the kind is. The kind and the content stay in the evidence, so a reviewer can check. | | The agent does not set a role. | The role is optional (R-005). Consumers use their own rule from the kind. The share of sources with a role is measurable from the evidence. | | The agent forgets the companion file for an image. | The image has no role, and consumers use their own rule. | +| A title holds a secret, for example a token in a pasted ticket title. | The redaction covers the header of a text file and the title of a companion file (R-008). | | A source has more than one purpose. For example, a ticket also holds the full spec. | The agent records the main purpose. The instruction says to pick the role that tells why the source is in the session. | From c2d92a688108f51fb2df3cac836eaa5a487eba24 Mon Sep 17 00:00:00 2001 From: "Jose I. Paris" Date: Tue, 6 Oct 2026 14:04:29 +0200 Subject: [PATCH 3/5] spec: 004 redact every title before it goes into the evidence Refs #3531 Signed-off-by: Jose I. Paris Chainloop-Trace-Sessions: d4043d7b-f121-41dd-a642-42aff4c66211 --- docs/specs/004-spec-source-role.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/specs/004-spec-source-role.md b/docs/specs/004-spec-source-role.md index 42098e74b..2848f1529 100644 --- a/docs/specs/004-spec-source-role.md +++ b/docs/specs/004-spec-source-role.md @@ -58,7 +58,7 @@ The header of a text spec file, and the companion file of a binary file, MAY hol - Done when: a ticket file with `title: "ENG-1234: Add an export button"` pushes a spec entry and a material annotation with that title. ### R-008: Title limits -The system MUST cut a title that is longer than 120 characters, and keep the first 120. The system MUST apply the secret redaction of Spec 002 to the title of a companion file before the title goes into the evidence. A bad title MUST NOT stop the push. +The system MUST cut a title that is longer than 120 characters, and keep the first 120. Each title MUST pass the secret redaction of Spec 002 before it goes into any evidence field. For a text file, the system MUST read the title from the redacted file, as it reads the source address. For a binary file, the system MUST redact the title of the companion file. A bad title MUST NOT stop the push. ## Constraints - The repository is public. The instruction text and the format are visible to all users. @@ -147,5 +147,5 @@ None. | The agent gives a wrong role, for example `spec` for a background document. | The role is the agent's statement, as the kind is. The kind and the content stay in the evidence, so a reviewer can check. | | The agent does not set a role. | The role is optional (R-005). Consumers use their own rule from the kind. The share of sources with a role is measurable from the evidence. | | The agent forgets the companion file for an image. | The image has no role, and consumers use their own rule. | -| A title holds a secret, for example a token in a pasted ticket title. | The redaction covers the header of a text file and the title of a companion file (R-008). | +| A title holds a secret, for example a token in a pasted ticket title. | Each title passes the redaction before it goes into the evidence (R-008). | | A source has more than one purpose. For example, a ticket also holds the full spec. | The agent records the main purpose. The instruction says to pick the role that tells why the source is in the session. | From cf2bf68653b0b3c2e3cf202864b65a552f1e23f5 Mon Sep 17 00:00:00 2001 From: "Jose I. Paris" Date: Tue, 6 Oct 2026 14:20:40 +0200 Subject: [PATCH 4/5] spec: 004 add an optional description to each spec source Refs #3531 Signed-off-by: Jose I. Paris Chainloop-Trace-Sessions: d4043d7b-f121-41dd-a642-42aff4c66211 --- docs/specs/004-spec-source-role.md | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/docs/specs/004-spec-source-role.md b/docs/specs/004-spec-source-role.md index 2848f1529..91fc2ad3b 100644 --- a/docs/specs/004-spec-source-role.md +++ b/docs/specs/004-spec-source-role.md @@ -4,10 +4,10 @@ ticket: https://github.com/chainloop-dev/chainloop/issues/3531 prd: --- -# Spec 004: Role and title of each spec source +# Spec 004: Role, title, and description of each spec source ## Summary -This spec changes the spec capture of [Spec 002](002-session-spec-capture.md) and [Spec 003](003-spec-capture-during-session.md). It does not replace them. Today each spec source has a kind: ticket, document, image, or text. The kind tells the format of a source, but not its purpose. A source also has no name that a person can read. With this change, the agent can also record a role and a title for each source. The role is `task`, `spec`, `plan`, or `reference`. The title is a short name, for example the title of a ticket. The CLI stores both in the session material and in the annotations of the spec material. A tool that shows the sources can then group them by purpose and label them by title. +This spec changes the spec capture of [Spec 002](002-session-spec-capture.md) and [Spec 003](003-spec-capture-during-session.md). It does not replace them. Today each spec source has a kind: ticket, document, image, or text. The kind tells the format of a source, but not its purpose. A source also has no name that a person can read. With this change, the agent can also record a role, a title, and a description for each source. The role is `task`, `spec`, `plan`, or `reference`. The title is a short name, for example the title of a ticket. The description says in one or two sentences what the source holds. The CLI stores these values in the session material and in the annotations of the spec material. A tool that shows the sources can then group them by purpose, label them by title, and explain each one. ## Problem - A reader of the evidence cannot tell a spec from a background document. Both have the kind `document`. @@ -18,13 +18,13 @@ This spec changes the spec capture of [Spec 002](002-session-spec-capture.md) an - An image or another binary file has no header, so the agent cannot record anything about it. ## Goals and Non-Goals -- Goal: each spec source can carry its purpose and a short title, as the agent decides them. -- Goal: the evidence holds the role and the title next to the kind, in the spec entry and in the material annotations. -- Goal: the agent can give a role and a title to a binary file too. -- Goal: sessions without roles or titles stay valid, and earlier consumers keep working. +- Goal: each spec source can carry its purpose, a short title, and a short description, as the agent decides them. +- Goal: the evidence holds these values next to the kind, in the spec entry and in the material annotations. +- Goal: the agent can give these values to a binary file too. +- Goal: sessions without these values stay valid, and earlier consumers keep working. - Non-goal: a change to the kinds, or to how the CLI finds the kind. -- Non-goal: rules in the CLI that guess a role or a title. The agent decides them, as it decides what a spec is (D-001 of Spec 002). -- Non-goal: a source address or other metadata for binary files. Only the role and the title are new. +- Non-goal: rules in the CLI that guess a role, a title, or a description. The agent decides them, as it decides what a spec is (D-001 of Spec 002). +- Non-goal: a source address or other metadata for binary files. Only the role, the title, and the description are new. - Non-goal: a change to the reminder at each user turn of Spec 003. ## Requirements @@ -40,7 +40,7 @@ A spec source MAY have one role. The roles are: The header of a text spec file MAY hold a `role` field. The CLI MUST read it with no regard to letter case. ### R-003: Role of a binary file -For an image or another binary file, the agent MAY write a companion file. Its name is the name of the binary file plus `.meta.yaml`. It holds a `role` field and a `title` field. The CLI MUST apply those values to the binary file. The CLI MUST NOT store the companion file as a spec material of its own. The CLI MUST ignore a companion file with no binary file next to it. +For an image or another binary file, the agent MAY write a companion file. Its name is the name of the binary file plus `.meta.yaml`. It holds the fields `role`, `title`, and `description`. The CLI MUST apply those values to the binary file. The CLI MUST NOT store the companion file as a spec material of its own. The CLI MUST ignore a companion file with no binary file next to it. - Done when: the agent copies a screenshot and writes its companion file with `role: reference`. The push records one image material with the role `reference`, and no material for the companion file. ### R-004: Role in the evidence @@ -51,7 +51,7 @@ A role that is missing, empty, or not in the vocabulary MUST give no role. The s - Done when: a header with `role: design` pushes a spec material with no role annotation, and the push succeeds. ### R-006: Capture instruction -The capture instruction at session start SHOULD ask the agent to set the role and the title of each source. It SHOULD give one short line for each role. It SHOULD tell the agent how to give a role and a title to a binary file. +The capture instruction at session start SHOULD ask the agent to set the role, the title, and the description of each source. It SHOULD give one short line for each role. It SHOULD tell the agent how to give these values to a binary file. ### R-007: Title The header of a text spec file, and the companion file of a binary file, MAY hold a `title` field. When a source has a title, the system MUST record it in the spec entry of the session material. It MUST also record it in a `chainloop.spec.title` annotation on the spec material. When the title is missing or empty, the system MUST leave out both. The system MUST NOT make a title from the content or from the file name. @@ -60,6 +60,9 @@ The header of a text spec file, and the companion file of a binary file, MAY hol ### R-008: Title limits The system MUST cut a title that is longer than 120 characters, and keep the first 120. Each title MUST pass the secret redaction of Spec 002 before it goes into any evidence field. For a text file, the system MUST read the title from the redacted file, as it reads the source address. For a binary file, the system MUST redact the title of the companion file. A bad title MUST NOT stop the push. +### R-009: Description +The header of a text spec file, and the companion file of a binary file, MAY hold a `description` field. It says in one or two sentences what the source holds, or why it is in the session. When a source has a description, the system MUST record it in the spec entry of the session material. It MUST also record it in a `chainloop.spec.description` annotation on the spec material. When the description is missing or empty, the system MUST leave out both. The system MUST NOT make a description from the content. The rules of R-008 apply, with a limit of 300 characters. + ## Constraints - The repository is public. The instruction text and the format are visible to all users. - The change to the evidence is additive. A consumer that does not know the role or the title MUST still read the spec entries and materials. @@ -76,6 +79,7 @@ kind: ticket uri: https://tracker.example.com/issue/ENG-1234 role: task title: "ENG-1234: Add an export button" +description: The ticket that the session implements. It asks for a CSV export on the report page. --- # ENG-1234: Add an export button @@ -92,6 +96,7 @@ spec folder ├── export-mockup.png image, stored as it is └── export-mockup.png.meta.yaml role: reference title: Export button mockup + description: Where the button goes. ``` At push time, the CLI reads the role and the title as it reads the kind and the source address. It normalizes the role, and it drops a role that is not in the vocabulary. It cuts a long title. It applies the values of a companion file to its binary file, after it redacts the title, and it does not upload the companion file. The spec entry and the material annotations then hold the role and the title: @@ -99,6 +104,7 @@ At push time, the CLI reads the role and the title as it reads the kind and the ```json "spec": [ { "kind": "ticket", "role": "task", "title": "ENG-1234: Add an export button", + "description": "The ticket that the session implements. It asks for a CSV export on the report page.", "uri": "https://tracker.example.com/issue/ENG-1234", "digest": "sha256:e4c2...", "captured_at": "2026-10-06T10:12:03Z" }, { "kind": "image", "role": "reference", "title": "Export button mockup", @@ -136,6 +142,7 @@ A tool that shows the sources groups them by role when a source has one, and lab | D-008 | Name of a source | An optional title that the agent writes, next to the role | The agent knows the title of the source when it writes the file. The format already changes for the role, so a second field costs little. A tool can label a source from the session material alone. Rejected: the material name only (a short lower-case file stem). Rejected: a title that the CLI takes from the first heading (a guess that looks like a fact in the evidence). This changes the outcome of [#3528](https://github.com/chainloop-dev/chainloop/issues/3528), which closed a title field before the format had other changes. | drafting | | D-009 | Where the title goes | The spec entry and a `chainloop.spec.title` annotation, as for the role | A tool that reads only one material can label it. Rejected: the spec entry only. | drafting | | D-010 | Long title | Cut at 120 characters, and keep the first part | A model sometimes writes a full paragraph. A cut keeps a usable label. Rejected: drop a long title (the source loses its label). Rejected: no limit (long annotations and labels). | drafting | +| D-011 | Description of a source | An optional description of one or two sentences, with the rules of the title and a limit of 300 characters | A reviewer sees why a source is in the session before opening it. Rejected: no description, because the content is the description (a reviewer must open each source to know what it is). | [PR comment](https://github.com/chainloop-dev/chainloop/pull/3532#discussion_r4195022169) | ## Open Questions None. From 77fc1ce628b24ff1abfac04db2ca2dcca29e764b Mon Sep 17 00:00:00 2001 From: "Jose I. Paris" Date: Tue, 6 Oct 2026 14:25:55 +0200 Subject: [PATCH 5/5] spec: 004 show the description in the binary file example Refs #3531 Signed-off-by: Jose I. Paris Chainloop-Trace-Sessions: d4043d7b-f121-41dd-a642-42aff4c66211 --- docs/specs/004-spec-source-role.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/specs/004-spec-source-role.md b/docs/specs/004-spec-source-role.md index 91fc2ad3b..c37e01cea 100644 --- a/docs/specs/004-spec-source-role.md +++ b/docs/specs/004-spec-source-role.md @@ -108,6 +108,7 @@ At push time, the CLI reads the role and the title as it reads the kind and the "uri": "https://tracker.example.com/issue/ENG-1234", "digest": "sha256:e4c2...", "captured_at": "2026-10-06T10:12:03Z" }, { "kind": "image", "role": "reference", "title": "Export button mockup", + "description": "Where the button goes.", "digest": "sha256:c2a1...", "captured_at": "2026-10-06T10:31:40Z" } ] ``` @@ -121,7 +122,8 @@ At push time, the CLI reads the role and the title as it reads the kind and the "chainloop.spec.session_id": "fd4e6754-3b26-4f54-9807-13c58465bb35", "chainloop.spec.kind": "image", "chainloop.spec.role": "reference", - "chainloop.spec.title": "Export button mockup" + "chainloop.spec.title": "Export button mockup", + "chainloop.spec.description": "Where the button goes." } } ```