Feedback
The feedback plugin is how an agent asks you questions. It sends a short form: choices, yes-or-no questions, free text and acknowledgments, in groups, with follow-up questions that appear only when an earlier answer calls for them. You answer everything in one pass and hand it back. It comes with the app, and the setup installs it.
When to use it
Section titled “When to use it”- Before starting work. Preferences the agent should not guess: which approach, which audience, how far to go.
- At a fork. A choice between options the agent has worked out, with its recommendation and reasoning.
- Before something irreversible. An explicit acknowledgment, such as “I understand this deletes the staging data”.
- Requirements gathering. A structured interview in place of a long back-and-forth in chat.
Use feedback when the agent needs information from you. When it needs a verdict on things it proposes to do, use List.
What you see
Section titled “What you see”- Groups of numbered questions, one after another. A rail on the left lists every group and its questions, with a dot for where each stands and an asterisk on each required question still to answer, and jumps to any of them.
- The agent’s recommendation, marked on the option it suggests and set out above the options with its reasoning. Nothing is preselected: the answer is yours, and Use this answer takes the recommendation in one click.
- Follow-up questions that appear when an earlier answer calls for them, and hide again if you change it.
- Limits on a multiple-choice question. Once you have chosen as many options as it allows, the others are disabled until you untick one.
- A comment on any choice question, to qualify your answer. Comments support Markdown. A comment shows as formatted text, and clicking it opens it for editing.
- Your previous answers, for reference, when the agent asks again in a new round.
Keys: J / K move to the next and previous question and put the focus on its answer, so the arrow keys or space answer it.
If you hand over with required questions unanswered, a bar above the hand-over button says how many are left, and Go to the first takes you to the first of them.
To see it before any agent asks with it, send its sample: pinrail submit feedback --sample, or Send a sample in its details in Settings › Plugins.
Asking from your agent
Section titled “Asking from your agent”## When you need a decision from me
When you need my input to go on, don't guess and don't ask in chat. Ask withPinrail's `feedback` plugin and wait:
1. Write the questions to a JSON file (the shape is below). Give every group and question a stable `id`. Offer choices when you can, and add a `recommendation` with your reasoning when you have one.2. Run: `pinrail submit feedback --title "<what you need to decide>" --data questions.json --wait`3. Use the answers as given. An answer's comment qualifies it; read it. Questions under `unanswered` got no answer: don't assume one.4. If the command exits 5, stop and tell me why.What the agent sends
Section titled “What the agent sends”{ "description": "Checkout is failing for 4% of users since the 3.2 deploy. I need a plan before I touch production.", "groups": [ { "id": "recovery", "title": "Recovery", "questions": [ { "id": "approach", "type": "single_choice", "prompt": "How should I proceed?", "required": true, "options": [ { "id": "rollback", "label": "Roll back to release 2.7", "description": "Fastest recovery." }, { "id": "patch", "label": "Apply the proposed patch", "description": "Keeps the new checkout flow." } ], "recommendation": { "answer": "rollback", "reason": "The previous release has a known-good payment path." } }, { "id": "preserve_logs", "type": "checkbox", "prompt": "Preserve logs before rolling back", "checkbox_label": "Keep the last 24 hours of payment logs", "required": true, "when": { "question_id": "approach", "operator": "equals", "value": "rollback" } } ] } ]}Question types
Section titled “Question types”type | Answer | Options |
|---|---|---|
single_choice | One option id | options: [{ id, label, description? }] |
multiple_choice | An array of option ids | options, min_selections, max_selections |
text | A string | placeholder, min_length, max_length |
boolean | true or false | Shown as Yes and No. No counts as an answer. |
checkbox | true or false | checkbox_label. A required one must be checked. |
Every question takes prompt, optional description (markdown) and required. Questions are optional unless required: true.
Follow-up questions
Section titled “Follow-up questions”A question or a whole group can have a when condition on an earlier question:
{ "all": [ { "question_id": "notify", "operator": "equals", "value": true }, { "question_id": "channels", "operator": "contains", "value": "email" }] }Operators are equals, not_equals, contains (for multiple choice) and answered. Combine them with all and any. A condition can only refer to questions that come before it.
What comes back
Section titled “What comes back”{ "answers": [ { "question_id": "approach", "answer": "rollback", "comment": "Preserve logs first." }, { "question_id": "preserve_logs", "answer": true, "comment": "" } ], "unanswered": [], "excluded": []}answersholds each answered question in order, with the person’s comment.unansweredlists optional questions the person skipped.excludedlists questions hidden by conditions. Their answers are never included.
There is no overall approve or reject: the answers are the decision, and the agent acts on them.
Reference
Section titled “Reference”The plugin’s manifest, and the schemas a payload and a decision are checked against, read from the plugin’s own files.
name | feedback |
|---|---|
version | 1.0.0 |
title | Feedback |
description | Questions answered in one pass: choices, yes or no, free text, each with an optional recommendation. |
use_when | You are blocked on decisions only the person can make, such as choices between options, missing facts or preferences, and want them answered before you go on. |
shortcuts |
|
{ "name": "feedback", "version": "1.0.0", "title": "Feedback", "description": "Questions answered in one pass: choices, yes or no, free text, each with an optional recommendation.", "use_when": "You are blocked on decisions only the person can make, such as choices between options, missing facts or preferences, and want them answered before you go on.", "summary": { "request": { "counts": [ { "items": "/groups/*/questions", "label": "question", "plural": "questions" } ] }, "outcome": { "counts": [ { "items": "/answers", "label": "answered", "tone": "success" }, { "items": "/unanswered", "label": "unanswered", "tone": "warning" }, { "items": "/excluded", "label": "excluded" } ] } }, "shortcuts": [ { "keys": "j", "does": "Next question" }, { "keys": "k", "does": "Previous question" } ], "settings_schema": { "type": "object", "properties": { "rail_open": { "type": "boolean", "title": "Group list open", "description": "Start with the list of groups beside the questions", "default": true } } }}- descriptionstring
Markdown shown above the questions: why the agent is asking.
at most 10000 chars
groupsobject[]required
The questions, in groups shown one after another. At most 100 questions in all.
1–25 items
- idstringrequired
An ID unique across the groups: a letter, then up to 79 letters, digits, _ or -.
matches
^[A-Za-z][A-Za-z0-9_-]{0,79}$ - titlestringrequired
The group's heading.
1–1000 chars
- descriptionstring
Markdown shown under the group's heading.
at most 10000 chars
whencondition, one of 4
Show the group only when this condition holds. A condition can refer only to questions in earlier groups.
question_id + operator
- question_idstringrequired
matches
^[A-Za-z][A-Za-z0-9_-]{0,79}$ - operatorstringrequired
"answered"
question_id + operator + value
- question_idstringrequired
matches
^[A-Za-z][A-Za-z0-9_-]{0,79}$ - operatorenumrequired
"equals""not_equals""contains" - valuestring | booleanrequired
- allcondition[]required
1–20 items · each a
condition, as above - anycondition[]required
1–20 items · each a
condition, as above
questionsquestion[]required
The group's questions, in order.
1–100 items
- idstringrequired
An ID unique across every question in the review: a letter, then up to 79 letters, digits, _ or -.
matches
^[A-Za-z][A-Za-z0-9_-]{0,79}$ - typeenumrequired
single_choice and multiple_choice questions need options. Questions of the other types must not have them.
"single_choice""multiple_choice""text""boolean""checkbox" - promptstringrequired
The question, as the person reads it.
1–1000 chars
- descriptionstring
Markdown shown under the prompt.
at most 10000 chars
- requiredboolean
Whether the person must answer before handing over. A required checkbox must be checked.
default
false whencondition, one of 4
Show the question only when this condition holds. The condition can refer only to earlier questions.
question_id + operator
- question_idstringrequired
matches
^[A-Za-z][A-Za-z0-9_-]{0,79}$ - operatorstringrequired
"answered"
question_id + operator + value
- question_idstringrequired
matches
^[A-Za-z][A-Za-z0-9_-]{0,79}$ - operatorenumrequired
"equals""not_equals""contains" - valuestring | booleanrequired
- allcondition[]required
1–20 items · each a
condition, as above - anycondition[]required
1–20 items · each a
condition, as above
optionsobject[]
The choices, for single_choice and multiple_choice. Option IDs must be unique within the question.
1–50 items
- idstringrequired
matches
^[A-Za-z][A-Za-z0-9_-]{0,79}$ - labelstringrequired
1–1000 chars
- descriptionstring
at most 10000 chars
recommendationobject
The answer the agent recommends, shown to the person. It must be a valid answer to the question: an option ID for single_choice, a list of option IDs for multiple_choice, true or false for boolean and checkbox, and text within the length limits for text.
- answerstring | boolean | string[] | nullrequired
- reasonstring
at most 10000 chars
- placeholderstring
Placeholder text for a text question.
at most 10000 chars
- checkbox_labelstring
The label beside a checkbox.
at most 10000 chars
- min_selectionsinteger
For multiple_choice only: the fewest options the person must choose. It must not exceed max_selections, and it must be at least 1 for a required question.
0–50
- max_selectionsinteger
For multiple_choice only: the most options the person may choose. It must not exceed the number of options.
0–50
- min_lengthinteger
For text only: the shortest answer allowed. It must not exceed max_length.
0–10000
- max_lengthinteger
For text only: the longest answer allowed.
0–10000
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Feedback request", "type": "object", "additionalProperties": false, "required": [ "groups" ], "properties": { "description": { "type": "string", "maxLength": 10000, "description": "Markdown shown above the questions: why the agent is asking." }, "groups": { "type": "array", "minItems": 1, "maxItems": 25, "items": { "type": "object", "additionalProperties": false, "required": [ "id", "title", "questions" ], "properties": { "id": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,79}$", "description": "An ID unique across the groups: a letter, then up to 79 letters, digits, _ or -." }, "title": { "type": "string", "minLength": 1, "maxLength": 1000, "description": "The group's heading." }, "description": { "type": "string", "maxLength": 10000, "description": "Markdown shown under the group's heading." }, "when": { "$ref": "#/$defs/condition", "description": "Show the group only when this condition holds. A condition can refer only to questions in earlier groups." }, "questions": { "type": "array", "minItems": 1, "maxItems": 100, "items": { "$ref": "#/$defs/question" }, "description": "The group's questions, in order." } } }, "description": "The questions, in groups shown one after another. At most 100 questions in all." } }, "$defs": { "condition": { "oneOf": [ { "type": "object", "required": [ "question_id", "operator" ], "additionalProperties": false, "properties": { "question_id": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,79}$" }, "operator": { "const": "answered" } } }, { "type": "object", "required": [ "question_id", "operator", "value" ], "additionalProperties": false, "properties": { "question_id": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,79}$" }, "operator": { "enum": [ "equals", "not_equals", "contains" ] }, "value": { "type": [ "string", "boolean" ] } } }, { "type": "object", "additionalProperties": false, "required": [ "all" ], "properties": { "all": { "type": "array", "minItems": 1, "maxItems": 20, "items": { "$ref": "#/$defs/condition" } } } }, { "type": "object", "additionalProperties": false, "required": [ "any" ], "properties": { "any": { "type": "array", "minItems": 1, "maxItems": 20, "items": { "$ref": "#/$defs/condition" } } } } ], "description": "A condition on an earlier question's answer. It may refer only to a question that comes before the question or group it controls. Use equals or not_equals with a choice ID for single_choice, true or false for boolean and checkbox, and text for text. Use contains with an option ID for multiple_choice. answered takes no value. all and any combine up to 20 conditions, nested at most 8 levels deep." }, "question": { "type": "object", "additionalProperties": false, "required": [ "id", "type", "prompt" ], "properties": { "id": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,79}$", "description": "An ID unique across every question in the review: a letter, then up to 79 letters, digits, _ or -." }, "type": { "enum": [ "single_choice", "multiple_choice", "text", "boolean", "checkbox" ], "description": "single_choice and multiple_choice questions need options. Questions of the other types must not have them." }, "prompt": { "type": "string", "minLength": 1, "maxLength": 1000, "description": "The question, as the person reads it." }, "description": { "type": "string", "maxLength": 10000, "description": "Markdown shown under the prompt." }, "required": { "type": "boolean", "default": false, "description": "Whether the person must answer before handing over. A required checkbox must be checked." }, "when": { "$ref": "#/$defs/condition", "description": "Show the question only when this condition holds. The condition can refer only to earlier questions." }, "options": { "type": "array", "minItems": 1, "maxItems": 50, "items": { "type": "object", "required": [ "id", "label" ], "additionalProperties": false, "properties": { "id": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,79}$" }, "label": { "type": "string", "minLength": 1, "maxLength": 1000 }, "description": { "type": "string", "maxLength": 10000 } } }, "description": "The choices, for single_choice and multiple_choice. Option IDs must be unique within the question." }, "recommendation": { "type": "object", "required": [ "answer" ], "additionalProperties": false, "properties": { "answer": { "oneOf": [ { "type": "string", "maxLength": 10000 }, { "type": "boolean" }, { "type": "array", "uniqueItems": true, "items": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,79}$" } }, { "type": "null" } ] }, "reason": { "type": "string", "maxLength": 10000 } }, "description": "The answer the agent recommends, shown to the person. It must be a valid answer to the question: an option ID for single_choice, a list of option IDs for multiple_choice, true or false for boolean and checkbox, and text within the length limits for text." }, "placeholder": { "type": "string", "maxLength": 10000, "description": "Placeholder text for a text question." }, "checkbox_label": { "type": "string", "maxLength": 10000, "description": "The label beside a checkbox." }, "min_selections": { "type": "integer", "minimum": 0, "maximum": 50, "description": "For multiple_choice only: the fewest options the person must choose. It must not exceed max_selections, and it must be at least 1 for a required question." }, "max_selections": { "type": "integer", "minimum": 0, "maximum": 50, "description": "For multiple_choice only: the most options the person may choose. It must not exceed the number of options." }, "min_length": { "type": "integer", "minimum": 0, "maximum": 10000, "description": "For text only: the shortest answer allowed. It must not exceed max_length." }, "max_length": { "type": "integer", "minimum": 0, "maximum": 10000, "description": "For text only: the longest answer allowed." } }, "allOf": [ { "if": { "properties": { "type": { "enum": [ "single_choice", "multiple_choice" ] } } }, "then": { "required": [ "options" ] }, "else": { "not": { "required": [ "options" ] } } } ] } }}answersobject[]required
at most 100 items
- question_idstringrequired
matches
^[A-Za-z][A-Za-z0-9_-]{0,79}$ - answerstring | boolean | string[] | nullrequired
- commentstringrequired
at most 5000 chars
- unansweredstring[]required
- excludedstring[]required
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Feedback response", "type": "object", "additionalProperties": false, "required": [ "answers", "unanswered", "excluded" ], "properties": { "answers": { "type": "array", "maxItems": 100, "items": { "type": "object", "required": [ "question_id", "answer", "comment" ], "additionalProperties": false, "properties": { "question_id": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,79}$" }, "answer": { "oneOf": [ { "type": "string", "maxLength": 10000 }, { "type": "boolean" }, { "type": "array", "uniqueItems": true, "items": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,79}$" } }, { "type": "null" } ] }, "comment": { "type": "string", "maxLength": 5000 } } } }, "unanswered": { "type": "array", "uniqueItems": true, "items": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,79}$" } }, "excluded": { "type": "array", "uniqueItems": true, "items": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_-]{0,79}$" } } }}- rail_openbooleanGroup list open
Start with the list of groups beside the questions
default
true
{ "type": "object", "properties": { "rail_open": { "type": "boolean", "title": "Group list open", "description": "Start with the list of groups beside the questions", "default": true } }}