Tools, resources, and prompt

Three tools, two resources, one prompt. The server name is vindex. Every string below is what the assistant sees; schemas are published as tool input and output schemas so clients can validate calls.

Server instructions

The server advertises these instructions to every client. They are why an assistant scores several stories one at a time and leads with the finding.

instructions
Vindex scores user stories against INVEST and returns percentages with reasoning.
Score one story per call. If the user has several stories, call score_story once
for each, in sequence, and present each result as it arrives. Pass the story's
tracker id so re-scores stay free. Present the finding first, then the percentages.

score_story

Scores one user story synchronously and returns the INVEST result. One POST /api/v1/score to the Vindex gateway per call; the score comes back in the same call.

  • readOnlyHint: false
  • destructiveHint: false
  • idempotentHint: true
  • openWorldHint: true

Description shown to the assistant

Score a user story against the six INVEST dimensions with Vindex. Returns an overall percentage, a health band, and per-dimension percentages with reasoning and improvement suggestions. Pass story_id (the Jira key, Azure DevOps work item id, or any stable id from the user’s tracker) so the story is counted once and every later score of it is free. Without story_id, the story is identified by its text: scoring the same text again is free, scoring edited text counts as a new story. Takes 2 to 10 seconds.

Input

json schema
{
  "type": "object",
  "properties": {
    "title":               { "type": "string", "minLength": 3,  "maxLength": 300 },
    "description":         { "type": "string", "minLength": 10, "maxLength": 20000 },
    "acceptance_criteria": { "type": "string", "maxLength": 20000 },
    "story_id":            { "type": "string", "maxLength": 200,
                             "description": "Stable id from the user's tracker. Strongly recommended." }
  },
  "required": ["title", "description"],
  "additionalProperties": false
}

Output (structured content)

Real result: story NW-108 from the Northwind sample backlog, 2026-09-17 (dimension text abbreviated)
json
{
  "story_id": "NW-108",
  "overall_percent": 38,
  "health": "at_risk",
  "dimensions": {
    "independent": { "percent": 40, "reasoning": "…", "suggestions": ["…"] },
    "negotiable":  { "percent": 60, "reasoning": "…", "suggestions": ["…"] },
    "valuable":    { "percent": 60, "reasoning": "…", "suggestions": ["…"] },
    "estimable":   { "percent": 20, "reasoning": "…", "suggestions": ["…"] },
    "small":       { "percent": 20, "reasoning": "…", "suggestions": ["…"] },
    "testable":    { "percent": 30, "reasoning": "…", "suggestions": ["…"] }
  },
  "recommendations": [
    "Add measurable acceptance criteria with baseline and target metrics (e.g., p95 scan-to-confirm time, scans/hour, error rate) and specify devices/network conditions for measurement.",
    "…"
  ],
  "identity": { "mode": "story_id" },
  "vindex": { "job_id": "f58ed328-…", "processing_ms": 22867 }
}
  • health is healthy (80 to 100), needs_review (60 to 79), or at_risk (0 to 59). A suggestion, not a gate.
  • recommendations are ordered, highest impact first. The first is the finding the assistant leads with.
  • identity.mode is story_id when the caller’s id was used and content_hash when the story was identified by its text.
  • The tool also returns a markdown text rendering (story id and percentage, band, finding, top recommendations, dimension table) for clients that do not render structured content.

Errors

Returned as tool results with isError: trueand one sentence: “Vindex did not respond in time. Try again in a moment.” (65-second ceiling), “Vindex is busy for your company, try again shortly.” (concurrency), or an allowance message when the company’s new stories are paused for the month. Re-scores of counted stories still succeed when the allowance is exhausted.

One story per call, by design

There is no batch tool. A batch stacks several inference calls behind one response and fails on client timeouts exactly when a backlog is large, and an assistant has no good way to display ten full results. If the user asks for several stories, the assistant calls score_story once per story, in sequence, and presents each result as it arrives.

get_usage

Reports the company’s story allowance for the current month. Reads the same records the Vindex Portal usage page shows, so the two never disagree.

  • readOnlyHint: true
  • idempotentHint: true

Input

json schema
{ "type": "object", "properties": {}, "additionalProperties": false }

Output

json
{
  "company": "Acme",
  "company_name_is_placeholder": false,
  "plan": "free",                      // free | starter | standard | pro | enterprise
  "period": { "start": "2026-09-01", "end": "2026-09-30", "timezone": "UTC" },
  "stories": { "counted_this_month": 7, "allowance": 10, "remaining": 3 },
  "state": "ok",                       // ok | exhausted
  "upgrade_url": "https://www.vindexgateway.com/pricing"
}

Text rendering: “Acme has scored 7 of Up to 10 stories this month on the free plan. 3 remain. Re-scoring counted stories is free.” When the company still carries its placeholder name the text adds a reminder to rename it in the Vindex Portal.

explain_invest

Returns the INVEST dimension definitions and the health bands. Served from the server itself; makes no Vindex call and uses no allowance, so the assistant can explain a result without spending anything.

  • readOnlyHint: true
  • idempotentHint: true
  • openWorldHint: false

Input

json schema
{
  "type": "object",
  "properties": {
    "dimension": { "type": "string",
                   "enum": ["independent", "negotiable", "valuable", "estimable", "small", "testable"] }
  },
  "additionalProperties": false
}

Without dimensionit returns all six plus the bands. With one, it returns that dimension’s definition, what Vindex looks for, and common failure patterns.

Resources

URIMIMEContent
vindex://invest/dimensionsapplication/jsonThe same content as explain_invest with no argument, for clients that load reference material as a resource
vindex://health-bandsapplication/json{ healthy: [80,100], needs_review: [60,79], at_risk: [0,59] } with labels

Resources are static in content, but the endpoint still requires a valid token like every request.

Prompt: score-story

Argument: story_id(optional). Clients surface prompts as slash commands or quick actions; this is the one-click “score whatever is in the chat” action.

prompt text
Score the user story currently in this conversation with Vindex.

Take the story exactly as it stands right now, whether the user pasted it, you
drafted it, or you wrote it together. Do not change a word. Split it into:
- title: the story's title or one-line summary
- description: the body of the story
- acceptance_criteria: the acceptance criteria, if there are any

Call the score_story tool with those fields, passing story_id when the user has
a tracker id for the story.

Present the result in this order:
1. The finding in plain language, first.
2. The overall percentage and the health band (Healthy, Needs review, At risk).
3. The per-dimension detail only if the user asks for it.

Vindex judges the story as written. Do not offer to rewrite or improve it unless
the user asks.

The prompt contains no instruction to rewrite, improve, or re-score. What the user does with the result is between the user and their assistant.

Vocabulary in every tool string

  • The unit is the story. Never “tickets”, never “scores” as a thing being used up.
  • Allowances are phrased “Up to N stories”. No per-story price appears anywhere.
  • Percentages only. Never a score out of ten.
  • Health bands: Healthy, Needs review, At risk. They are suggestions.