Personas.linux-x64
0.4.11
dotnet add package Personas.linux-x64 --version 0.4.11
NuGet\Install-Package Personas.linux-x64 -Version 0.4.11
<PackageReference Include="Personas.linux-x64" Version="0.4.11" />
<PackageVersion Include="Personas.linux-x64" Version="0.4.11" />
<PackageReference Include="Personas.linux-x64" />
paket add Personas.linux-x64 --version 0.4.11
#r "nuget: Personas.linux-x64, 0.4.11"
#:package Personas.linux-x64@0.4.11
#addin nuget:?package=Personas.linux-x64&version=0.4.11
#tool nuget:?package=Personas.linux-x64&version=0.4.11
Persona Agent
A local-first .NET 10 tool that builds an evidence-grounded reviewer persona of a specific engineer from their history (PRs, review comments, commits, code, docs) and uses it to answer questions and review pull requests the way that person would — in their voice, scoped to their expertise, and with every finding traceable to real evidence.
It is designed to run in addition to generic AI reviewers: it targets the small, repeated, domain-specific issues a particular engineer reliably flags, so the human expert can focus on the hard problems.
How it works
ingest normalize PRs / comments / commits / code / docs from
Azure DevOps, GitHub, local Git, and folders
-> index evidence chunks -> SQLite FTS5 (BM25) + local ONNX embeddings, fused with RRF
-> build cluster the persona's recurring review comments, mine deterministic
"matcher" checks from them via Copilot, back-test each against history,
and write a versioned persona pack (memory, rubric, tone, mined checks)
-> review run the mined checks on a PR diff (deterministic, evidence-anchored),
merged ahead of the LLM's fuzzy residue, severity-ordered
-> eval / feedback measure precision/recall against history; record reviewer reactions
so dismissed checks stop firing
Key properties:
- Evidence-grounded. Every persona memory, rubric rule, and mined check cites real artifacts. A review finding without a citation (or pointing away from a changed line) is suppressed.
- Precision-first. Mined checks are kept only if they back-test well against the PRs whose comments produced them. Reviewer feedback suppresses checks the team keeps dismissing.
- Local & offline-capable. SQLite + local ONNX embeddings; no cloud vector DB. The only LLM dependency is the GitHub Copilot SDK, and every LLM path falls back to deterministic behavior on failure.
- Team mode. Run several personas over one PR and merge their findings, attributed to whoever raised each.
Requirements
- .NET SDK 10
- Optional: GitHub Copilot CLI / SDK auth for LLM-backed mining and review (
llm.provider: github-copilot-sdk) - Optional: local ONNX embedding model in
models/for semantic search (keyword search works without it) - Optional: Git CLI for
localGitingestion - Optional: Azure login compatible with
DefaultAzureCredential(or a PAT) for live Azure DevOps ingestion - Optional: a GitHub token for GitHub ingestion / PR review
Download the shared embedding model once:
./scripts/download-model.ps1 # writes models/all-MiniLM-L6-v2.onnx and models/vocab.txt
Examples below use
persona <command>. From source, that isdotnet run --project "src/Persona.Cli/Persona.Cli.csproj" -- <command>. Build a single-filepersonaexecutable with./scripts/publish.ps1 -Runtime win-x64.
Quick start
persona init --data persona-data --force
# edit persona-data/persona.yaml: set a real source + persona identity
persona validate --data persona-data
persona ingest --data persona-data
persona index --data persona-data
persona build --data persona-data --persona payments-expert
persona review --data persona-data --persona payments-expert --diff change.diff
persona eval --data persona-data --persona payments-expert
Every command prints a single JSON object on stdout (PascalCase properties) and returns a deterministic exit code, so it composes cleanly in scripts and CI.
End-to-end runbook
The examples use persona id payments-expert; substitute your own. --config <path> selects a manifest other than the data directory's persona.yaml. --data <path> is required whenever your dataDirectory is not the default ./persona-data.
1. Initialize and validate
persona init --data persona-data --force
persona validate --data persona-data
persona ado-validate --data persona-data # live ADO probe (only if you configured ADO)
validate returns status: valid with errors: []. ado-validate probes each configured Azure DevOps source (repository listing, sample PR threads/commits/iterations/work items) with retries on 429/502/503/504. Resolve any errors before ingesting.
2. Ingest evidence
persona ingest --data persona-data
Writes provider-native JSON under raw/ and provider-neutral normalized/*.jsonl. Ingestion captures, where available: PRs, review comments (with thread resolution status and reactions/votes), commits, changed files, work items, local-git commits + C#/TypeScript/JavaScript symbols/chunks, and documents/transcripts. For Azure DevOps, real unified diffs are fetched only for files that received review comments (no unrelated files/PRs). maxPullRequests per source caps ingestion volume.
Targeted re-ingest of only ADO PR iteration changes:
persona ingest --data persona-data --code-changes-only
3. Index for search
persona index --data persona-data
Writes indexes/evidence-chunks.jsonl and indexes/evidence.db (SQLite + FTS5, plus ONNX embedding blobs). If the model files under models/ are missing, the output reports embeddings disabled and FTS5 keyword search still works.
4. Resolve identity candidates
build resolves persona aliases against PR/commit/comment authors. Anything it cannot confidently resolve is listed under unresolvedCandidates. Approve or reject manually (persisted in personas/<id>/identity-overrides.json, applied by build/ask/review/eval and stable across rebuilds):
persona identity list --data persona-data --persona payments-expert
persona identity approve --data persona-data --persona payments-expert --candidate "azure-devops:alice@example.com" --reason "verified alias"
persona identity reject --data persona-data --persona payments-expert --candidate "local-git:bot@example.com" --reason "service account"
5. Build the persona pack
persona build --data persona-data --persona payments-expert
Writes personas/payments-expert/persona-pack.json plus the exploded companions (memory.json, review-rubric.json, tone-profile.json, evidence-map.json, matcher-specs.json, build-report.json) and per-stage diagnostics under build-stages/.
With llm.provider: github-copilot-sdk the build also mines matcher specs: it clusters the persona's recurring comments, asks Copilot (concurrently — one fresh CLI instance per cluster, default 10) to express each cluster as a deterministic check, back-tests each candidate against the historical diffs whose comments produced it, and keeps only those clearing the recall / false-positive thresholds. Deterministic builds mine nothing.
6. Ask and review
persona ask --data persona-data --persona payments-expert --query "How should we review retry behavior?"
persona review --data persona-data --persona payments-expert --diff change.diff --persist-run-artifacts
review runs the persona's mined checks over the diff and merges those deterministic, evidence-anchored findings ahead of the LLM's residue, deduped by file/line and ordered by the severity ladder. --persist-run-artifacts writes context-pack.json / agent-input.json / agent-output.json / verified-output.json under runs/<runId>/ for debugging.
Review a live PR — by number, or just paste its browser URL — instead of a diff file:
persona review --data persona-data --persona payments-expert --ado-pr 12345 --repo checkout-service
persona review --data persona-data --persona payments-expert --gh-pr 42 --repo checkout-service
# Or paste the PR's browser URL: provider/org/project/repo/id are parsed from it, so you need no
# --repo (and no persona.yaml source) — ideal for one-off dnx/NuGet reviews. Alias: --url.
persona review --persona payments-expert --pr-url "https://dev.azure.com/my-org/MyProject/_git/checkout-service/pullrequest/12345"
persona review --persona payments-expert --pr-url "https://github.com/my-org/checkout-service/pull/42"
Team / domain review — pass --persona more than once. Findings are merged and attributed to whichever personas raised them (mode: team, plus per-persona summaries):
persona review --data persona-data --persona payments-expert --persona platform-expert --diff change.diff
7. Evaluate and calibrate
persona eval --data persona-data --persona payments-expert
With no --eval-file, eval performs historical replay: it picks PRs the persona actually reviewed, hides their comments, re-reviews the diff, and scores recovery. Primary metrics are precision and category recall; misses are attributed to retrieval vs. reasoning vs. verification. The report also includes a threshold calibration suggestion — the lowest review.minConfidence whose false-positive rate stays within target (default 0.25), maximizing recall. It is a suggestion only; nothing is rewritten.
To apply that suggestion, run calibrate (a dry-run by default; --apply surgically writes review.minConfidence into persona.yaml, preserving comments):
persona calibrate --data persona-data --persona payments-expert # report the suggestion
persona calibrate --data persona-data --persona payments-expert --apply # write it to persona.yaml
Benchmark several personas at once with scripts/eval-personas.ps1 (a comparison table + combined JSON report).
Diagnose retrieval bottlenecks for hidden comments:
persona eval-diagnose --data persona-data --persona payments-expert
Fixture-based smoke check instead of replay: persona eval --eval-file cases.json (schema under Eval).
8. Close the feedback loop
After deployment, record how reviewers reacted to the persona's findings. Once a mined spec (or an LLM finding category) accrues enough dismissals it is suppressed in later reviews (so the persona stops re-raising rejected checks):
persona feedback --data persona-data --persona payments-expert --spec "matcher:payments-expert:reliability:0" --outcome dismissed --reason "noisy"
persona feedback --data persona-data --persona payments-expert --spec "matcher:payments-expert:testing:1" --outcome accepted
persona feedback --data persona-data --persona payments-expert --category maintainability --outcome dismissed --reason "too nitpicky"
--outcome is accepted | fixed | dismissed | false-positive. Provide exactly one of --spec (the matcher-spec prefix of a review finding's id) or --category (an inferred review category such as security or maintainability, suppressing repeatedly-dismissed LLM findings). Stored append-only under feedback/<persona>.jsonl.
9. Retrain on another machine
Everything needed to retrain lives in the repo, on NuGet (the Personas CLI), or on your Azure DevOps/Artifacts feed — except two git-ignored things: the embedding model and the tuned recipe (persona-data/persona.yaml, which holds real reviewer emails). The recipe's tuning is preserved in a committed, email-redacted template, persona-data/persona.sample.yaml, so it can never be lost. On a second machine with repo + ADO/feed access:
git clone <repo>; cd personas
az login # ADO + private-feed auth (DefaultAzureCredential / credential provider)
./scripts/download-model.ps1 # writes the git-ignored models/all-MiniLM-L6-v2.onnx + models/vocab.txt
# Recipe: copy the committed template to the real (git-ignored) config, then fill the redacted emails.
Copy-Item persona-data/persona.sample.yaml persona-data/persona.yaml
# edit persona-data/persona.yaml: replace each REPLACE_WITH_*_EMAIL@... identity with the real address
persona validate --data persona-data
# Retrain (fresh ADO evidence): ingest -> index -> build for every persona (omit --persona for all).
persona refresh --data persona-data # incremental; add --force to rebuild unchanged personas
# Package the retrained personas under privacy aliases and push to the private feed (bump the version).
./scripts/publish-trained-personas.ps1 -Version <next> -Push -Interactive
From a clone, persona is dotnet run --project src/Persona.Cli/Persona.Cli.csproj -- (see the note under Requirements); with NuGet access you can instead use the published tool, dnx Personas <command>.
- Same recipe, fresh evidence.
refreshre-pulls live ADO PRs at that moment, so a retrain is not byte-identical to a prior build (newer history + LLM nondeterminism). The tuning — sources, per-persona scope, per-persona retrieval budgets, matcher-mining thresholds — is reproduced exactly from the template. - If ADO identity resolution surfaces unmatched candidates, approve them (see step 4) and re-run
refresh. - NuGet versions are immutable, so bump
-Versionon every push. - Keep the template in sync: if you change
persona-data/persona.yaml, mirror the change intopersona-data/persona.sample.yaml(emails redacted) so the recipe stays version-controlled.
Configuration
persona init writes a documented persona.yaml. Key sections:
Config file discovery
Review/ask/eval/MCP resolve a config file from the first that exists, in order: explicit --config <path> →
the config in an explicitly passed --data <project> directory (persona.yaml / personas.{yaml,json} /
config.yaml) → $PERSONAS_HOME/personas.{yaml,json} → $XDG_CONFIG_HOME/personas/personas.{yaml,json}
(falling back to ~/.config when XDG_CONFIG_HOME is unset) → the default data directory's config (a low
fallback, so a stray sample in ~/.personas never shadows an explicit PERSONAS_HOME/XDG config) → built-in
defaults. Config files may be YAML or JSON. Installed persona manifests are then merged, so installed
personas run with no config file at all.
Data directory
Where all persona data lives (installed personas, evidence, indexes, runs) is resolved separately, in order:
--data <path> → $PERSONAS_HOME → a global config's dataDirectory: (from a PERSONAS_HOME/XDG config;
relative paths resolve against the config file's folder) → ~/.personas. A dataDirectory: in a config that
sits inside the data directory (e.g. an init-generated persona.yaml) is ignored, since it would be
self-referential -- only a global config redirects. So one XDG config can point every command at, say,
C:/temp/personas. (In YAML, leave the path unquoted or use forward slashes; a double-quoted scalar treats
backslashes as escapes.)
Sources
sources:
azureDevOps:
- name: main-ado
organizationUrl: https://dev.azure.com/my-org
project: MyProject
authentication: auto # auto | default-azure-credential | az-cli | pat
patEnvironmentVariable: AZDO_PAT
maxPullRequests: 100
repositories: [checkout-service, billing-api]
github:
- name: main-github
apiBaseUrl: https://api.github.com
owner: my-org
authentication: auto # auto | token | pat | none
tokenEnvironmentVariable: GITHUB_TOKEN
maxPullRequests: 100
repositories: [checkout-service]
localGit:
- name: checkout-service
path: C:/src/checkout-service # reads git log + C#/TypeScript/JavaScript symbols/chunks
documents:
- name: architecture-docs
path: ./docs
include: ["**/*.md"]
exclude: []
transcripts:
- name: design-reviews
enabled: true
path: ./transcripts
include: ["**/*.md", "**/*.txt"]
- ADO
autotriesDefaultAzureCredential, thenaz account get-access-token --resource 499b84ac-1321-427f-aa17-267ca6975798, then the PAT env var. Sample values (e.g.my-org) are skipped with a warning. maxPullRequestsis the primary guard on the build-time budget for prolific reviewers.
Personas
personas:
payments-expert:
displayName: Payments Expert
toneMimicryPercent: 100
identities:
- { kind: email, value: alice@example.com }
- { kind: azure-devops-user-id, value: aad-user-id-123 }
scope:
repositories: [checkout-service, billing-api]
includeArtifacts: [authored_prs, reviewed_prs, review_comments, docs, transcripts]
Identity kinds include email, azure-devops-user-id, azure-devops-descriptor, github-login, github-user-id, and git-author. Define as many personas as you like; run them individually or together (team mode).
LLM
llm:
provider: github-copilot-sdk # github-copilot-sdk | deterministic | disabled
defaultModel: auto # or a model id, e.g. claude-opus-4.8 (see `personas models`)
reasoning: { personaBuild: medium, ask: medium, review: high, verify: medium } # per model, e.g. low|medium|high|xhigh|max
# Optional context-window overrides (tokens); unset = the model default. A larger window also auto-scales
# both the evidence character budget AND the retrieval depth (when --top is not passed) up to the persona's
# trained budget, so a dense persona's full depth is used.
# maxContextWindowTokens: 1000000
# timeoutMinutes: 20 # per-LLM-call timeout; unset scales with reasoning effort ("max" gets the most)
# maxPromptTokens: 900000
# maxOutputTokens: 64000
github-copilot-sdk uses the official GitHub.Copilot.SDK; any failure falls back to deterministic, citation-first output with a warning. deterministic/disabled are fully local (used by the test suite and offline runs); they also skip matcher mining. Run personas models to list the exact model ids and each model's supported reasoning efforts. review --model <id> / --reasoning <effort> override the config for a single run.
Review (incl. feedback)
review:
maxFindings: 10
minConfidence: medium # global floor (low|medium|high)
categoryMinConfidence: {} # per-category overrides, e.g. security: high
postComments: false
focus: auto # auto | single | per-file (auto infers from reviewer density)
maxReviewGroups: 6 # cap on file-scoped sub-reviews when focus resolves to per-file
maxReviewConcurrency: 6 # how many of those sub-reviews run at once (one wave at 6)
deduplication: # opt-in semantic de-dup of findings; off by default
mode: none # none | llm (llm groups findings that make the same point)
scope: within-file # within-file (keeps per-file comments) | cross-file
feedbackDismissalThreshold: 0.5 # suppress a spec dismissed at/above this rate ...
minFeedbackSamples: 3 # ... once it has this many recorded reactions
When focus resolves to per-file, the diff is split into file-scoped groups reviewed concurrently (up to maxReviewConcurrency, capped at maxReviewGroups), then merged — reducing guidance dilution on wide PRs. De-duplication is off by default; set mode: llm to have the model group findings that make the same point (different wording, same line/file) and keep one representative, recording the rest in the suppressed-findings audit. scope: within-file (the default) preserves per-file comments; cross-file also merges a concern spanning files. Enable it per run with review --mode llm [--scope within-file|cross-file], or validate a strategy on labelled findings with dedup-eval. It was chosen LLM-only over embedding/hybrid clustering on the evidence: on labelled findings, embedding cosine could not separate true duplicates from distinct issues that merely share vocabulary, while LLM adjudication scored precision = recall = 1.0.
Persona build (incl. matcher mining)
personaBuild:
enableMatcherMining: true # github-copilot-sdk only
matcherMiningConcurrency: 10 # fresh Copilot CLI instance per cluster
minMatcherClusterSupport: 3 # min distinct comments before mining a cluster
minMatcherRecall: 0.5 # back-test gate (recall over source PRs)
maxMatcherFalsePositiveRate: 0.25 # back-test gate (firing on non-commented files)
# extraction floors:
minDeterministicCategoryRescueCount: 3
minDeterministicMemoryKindRescueCount: 3
minMemoryStatementLength: 20
minRubricTitleLength: 12
minRubricDescriptionLength: 20
Retrieval
retrieval: { maxContextItems: 40, keywordTopK: 50, semanticTopK: 50, finalTopK: 40 }
Copilot environment variables
PERSONA_COPILOT_GITHUB_TOKEN— explicit GitHub token for the SDKPERSONA_COPILOT_CLI_PATH/PERSONA_COPILOT_CLI_URL— spawn a specific Copilot CLI binary over stdio / connect to a running runtime. If neither is set and the tool does not bundle the CLI (aCopilotSkipCliDownloadbuild), acopilot/copilot.exeonPATHis discovered automatically (bring-your-own-Copilot); otherwise the SDK's bundled runtime is used.PERSONA_COPILOT_HOME— Copilot state directoryPERSONA_COPILOT_LOG_LEVEL— CLI log level (defaulterror)PERSONA_COPILOT_TIMEOUT_MINUTES— override the per-call timeout (minutes); unset scales with the review/ask reasoning effort (low→5,medium→8,high→12,xhigh→15,max→20)PERSONA_COPILOT_SDK_DISABLED=true— force deterministic fallback (tests / offline)PERSONA_DUMP_RAW_FINDINGS_PATH— debug: write the raw per-group findings (pre-merge/dedup) to this path as JSON- Embedding model paths come from
embedding.modelPath/embedding.vocabPath.
Commands
| Command | Purpose |
|---|---|
init |
Create the data directory layout and a sample persona.yaml |
version |
Print CLI version metadata |
status |
Report local data-directory counts as JSON |
validate |
Validate persona.yaml; report errors/warnings |
ado-validate |
Live-probe configured Azure DevOps sources |
ingest |
Fetch + normalize source artifacts (--code-changes-only for ADO re-ingest) |
index |
Build evidence chunks + SQLite FTS5/embedding index |
search |
Hybrid BM25 + semantic search over evidence (--query, --top) |
build |
Build the persona pack (incl. matcher-spec mining) |
refresh |
One-shot incremental ingest → index → build for a persona (or all); unchanged personas are reused |
ask |
Answer a question with citations (--query) |
review |
Review a diff or PR; --diff, --ado-pr/--gh-pr + --repo (or --pr-url <url> to paste the PR's browser URL; add --ado-org+--project to skip config), repeat --persona for team mode, --model/--reasoning to override the LLM, --mode llm [--scope within-file\|cross-file] for opt-in finding de-dup |
eval |
Historical replay (or --eval-file fixtures) + threshold calibration |
eval-diagnose |
Classify hidden-comment retrieval bottlenecks |
calibrate |
Replay to suggest review.minConfidence; --apply writes it to persona.yaml |
dedup-eval |
Calibration: run the LLM finding de-dup over a findings JSON and report merges + pair precision/recall vs optional ground-truth labels (--mode none\|llm, --scope within-file\|cross-file) |
models |
List the GitHub Copilot models available to you (id + supported reasoning efforts) for llm.defaultModel / llm.reasoning |
identity |
list / approve / reject unresolved identity candidates |
feedback |
Record reviewer reaction to a finding (--spec matcher, or --category LLM finding) + --outcome |
export |
Export a persona to a portable .persona bundle (--pack brain-only, --full default) |
pack |
Package one or more personas into a NuGet package (--package-id, repeat --persona) |
pack-diff |
Compare two persona packs (names, persona-pack.json/dirs, or .persona bundles) and emit a changelog |
install |
Install personas from .persona files, or a NuGet feed (--source) |
list |
List installed/built personas in the data directory |
uninstall |
Remove an installed persona |
mcp |
Start the MCP server (stdio) for VS Code Copilot / the GitHub Copilot CLI |
Global flags: --data <path>, --config <path>, --top <n>, --output-file <path>, --persist-run-artifacts, --run-artifacts-dir <path>, --force.
review/ask show a live progress indicator (stage + elapsed) on stderr so a slow high-reasoning run doesn't look like a hang — on by default in an interactive terminal, off when redirected (agents/CI/pipes). Force it with --progress or off with --no-progress (alias --quiet). It never touches the JSON on stdout.
Eval
Fixture file schema for persona eval --eval-file cases.json:
{
"cases": [
{ "id": "ask-idempotency", "kind": "ask", "personaId": "payments-expert",
"query": "How should idempotency behave during retry storms?",
"expectedContains": ["Payments Expert"], "requireCitations": true },
{ "id": "review-idempotency", "kind": "review", "personaId": "payments-expert",
"diffPath": "change.diff", "requireCitations": true, "minFindings": 1 }
]
}
Data layout
persona-data/
persona.yaml
raw/ provider-native JSON, kept before normalization
normalized/ *.jsonl: pull-requests, review-comments, commits, code-changes,
work-items, documents, transcripts, code-symbols, code-chunks
indexes/ evidence-chunks.jsonl, evidence.db (SQLite + FTS5)
personas/<id>/ persona-pack.json + memory/review-rubric/tone-profile/evidence-map/
matcher-specs/build-report.json, build-stages/, identity-map.json,
identity-overrides.json
feedback/ <persona>.jsonl (reviewer reactions)
runs/<runId>/ persisted ask/review/eval artifacts
Run as a published tool (dnx)
Personas is published to NuGet as Personas — one framework-dependent package per platform
(win-x64/arm64, osx-arm64, linux-x64/arm64); the right one is selected automatically. The embedding model is
baked in, so installed personas work with no extra downloads. Run it without installing using dnx
(.NET 10's npx-equivalent), or install it globally:
# one-shot, no install (resolves + caches the tool on first use):
dnx Personas review --persona <name> --diff change.diff --output-file review.json
# or install once; the command is then `personas`:
dotnet tool install -g Personas
personas review --persona <name> --diff change.diff --output-file review.json
--output-file <path> writes the JSON result to a file (recommended for automation); stdout then prints
only {"status":"ok","outputFile":"..."}. With no --data, the data directory defaults to PERSONAS_HOME
(~/.personas).
MCP server (VS Code Copilot & GitHub Copilot CLI)
personas mcp starts a Model Context Protocol server over stdio (built on
the official ModelContextProtocol .NET SDK) so coding agents can use an installed persona. It exposes
read/compute-only tools:
| Tool | What it does |
|---|---|
review_pull_request |
Review a change as a persona — a unified diff (diffPath/diffText) or a live Azure DevOps / GitHub PR (azureDevOpsPullRequestId/gitHubPullRequestId + repository); returns evidence-grounded findings |
team_review |
Review one change with several personas at once and merge their findings, each attributed to the personas that raised it |
ask_persona |
Ask a persona a question, answered from its pack + evidence |
search_persona_evidence |
Search a persona's evidence corpus (no LLM call) |
list_personas |
List installed/built personas |
get_persona_profile |
Return a persona's rubric, memories, and tone for in-session reviewing |
Install the tool first so the server's stdout stays a clean JSON-RPC channel (prefer an installed
personas mcp over dnx as the launch command), then register it with your client:
// VS Code — .vscode/mcp.json (the GitHub Copilot CLI takes an equivalent MCP config)
{
"servers": {
"personas": { "type": "stdio", "command": "personas", "args": ["mcp"] }
}
}
Then, in agent mode, ask e.g. "Review this PR as matan." The review_pull_request / team_review / ask_persona tools
drive the persona's Copilot engine, so they need GitHub Copilot auth (the same login you already use); the
other tools are pure reads. The server resolves personas from --data (PERSONAS_HOME by default) and writes
all logs to stderr.
Distribute personas
Ship a built persona as a portable .persona bundle, or as a NuGet package containing one or more personas:
# Export to a .persona file (full tier by default; --pack for the brain only):
personas export --persona <id> --out <id>.persona
# Package one or more personas into a NuGet, then push:
personas pack --package-id MyTeam.Personas --persona <id> [--persona <id2>] --package-version 1.0.0 --out ./out
dotnet nuget push ./out/MyTeam.Personas.1.0.0.nupkg --source <feed> --api-key <key>
# Install (from a file or a feed), then run by name with no persona.yaml:
personas install ./<id>.persona
personas install MyTeam.Personas --source <feed>
personas list
Installing from an authenticated feed (e.g. Azure Artifacts) uses the same auth as dotnet/dnx: the
Azure Artifacts Credential Provider plus your Az CLI token (az login) — no prompt. For a first-time
interactive (device-flow) sign-in, add --interactive. A 401/403 returns a clean auth_error with guidance
(not a stack trace).
Agent skills
skills/ contains Agent Skills that teach AI agents to drive this CLI:
review-with-persona, create-persona, and distribute-personas (each a SKILL.md plus PowerShell Core
helper scripts under scripts/).
Troubleshooting
- Semantic search disabled — expected until
models/all-MiniLM-L6-v2.onnxandmodels/vocab.txtexist; run./scripts/download-model.ps1. Keyword search still works. - Azure DevOps skips ingestion — check
organizationUrlisn't the sample value,projectis set,authenticationis supported, and the shell can authenticate (orAZDO_PATis set). - Ask/review says persona pack missing — run
persona build --persona <id>first. - Copilot falls back to deterministic — auth/SDK startup failed; the run still completes with a warning. Force it locally with
$env:PERSONA_COPILOT_SDK_DISABLED = "true". - Invalid YAML — run
persona validate; parser errors are returned as JSON validation errors.
Development
dotnet build "PersonaAgent.slnx"
dotnet test "PersonaAgent.slnx"
./scripts/publish.ps1 -Runtime win-x64
Limitations
- The GitHub Copilot SDK integration uses the public preview SDK and may need updates if its API changes; it has not yet been validated against a live account end-to-end in this environment.
- Live Azure DevOps / GitHub API behavior is covered by test doubles but should be validated against a real org before relying on it.
- Code structural analysis covers C# (Roslyn) and TypeScript/JavaScript (a dependency-free heuristic analyzer); other languages rely on the regex/manifest/path matcher primitives.
- GitHub inline-comment thread resolution requires GraphQL and is not yet captured (reactions are).
Learn more about Target Frameworks and .NET Standard.
This package has no dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.