Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

persona-dsl

persona-dsl — Python framework для E2E-, API- и интеграционных тестов на Screenplay-подходе, native runner, discovery, reporting, generators и MCP/read-only tooling.

Структура

  • src/persona_dsl/ — framework package.
  • tests/ — package tests.
  • scripts/ — package tooling.
  • template/ — официальный starter project.
  • docs/ — правила и инженерные принципы.

Установка

Новый проект создаётся standalone bootstrap-скриптом из выбранного release tag. Скрипт проверяет Python >=3.12, создаёт project-local .venv, устанавливает выбранную Persona distribution и выполняет полный project reconcile, настройку агентской среды и doctor. Значение latest включает stable, alpha, beta и RC. Интерактивный запуск сразу предлагает настроить Atlassian MCP, CSS embeddings и Zephyr Server MCP. Бездиалоговый запуск для CI использует флаг --yes и пропускает только вопросы о необязательных интеграциях.

POSIX shell:

PERSONA_RELEASE="<release-tag>"
PERSONA_RELEASE_URL="https://github.com/pglyanenko/persona/releases/download/${PERSONA_RELEASE}"
curl -fLO "${PERSONA_RELEASE_URL}/install-persona.py"
curl -fLO "${PERSONA_RELEASE_URL}/install-persona.py.sha256"
shasum -a 256 -c install-persona.py.sha256
python3 install-persona.py --project-root ./persona-project --version latest

PowerShell:

$PersonaRelease = "<release-tag>"
$PersonaReleaseUrl = "https://github.com/pglyanenko/persona/releases/download/$PersonaRelease"
Invoke-WebRequest "$PersonaReleaseUrl/install-persona.py" -OutFile install-persona.py
Invoke-WebRequest "$PersonaReleaseUrl/install-persona.py.sha256" -OutFile install-persona.py.sha256
$Expected = (Get-Content install-persona.py.sha256).Split()[0].ToLowerInvariant()
$Actual = (Get-FileHash install-persona.py -Algorithm SHA256).Hash.ToLowerInvariant()
if ($Actual -ne $Expected) { throw "SHA-256 checksum mismatch" }
py install-persona.py --project-root ./persona-project --version latest

Для уже созданного проекта единый lifecycle запускается из его корня:

make install
make agent

В CI используется dependency-only подготовка окружения:

make ci-install
make checks

make ci-install создаёт или переиспользует .venv, устанавливает зависимости проекта и Allure. Команда не выполняет project reconcile, agent init и doctor и не материализует agent, MCP, LSP, memory или workflow surface.

Разработка framework

make install
make checks
make knowledge-check
make package-smoke

UI adapters

Persona связывает browser observation, Page generation, runtime resolution и component operations через один UiComponentAdapter. Встроенный persona-core pack покрывает native HTML, ARIA, Ant Design, UIkit, AG Grid, MUI X, Radix и React Spectrum. Project-specific design systems подключаются один раз через ui_adapters.modules, установленные packs — через entry-point group persona.ui_adapters и ui_adapters.packages. Page fields не содержат adapter id: registry автоматически выбирает pack по DOM owner, topology и identity. UI-действие ожидает появление owner через lazy candidates совместимых adapters, повторяет deterministic match и передаёт оставшийся state contract выбранному operation runtime; отдельный WaitFor* только ради target не требуется.

persona ui-adapters list --project-root . --env dev
persona ui-adapters inspect ant-select --project-root . --env dev
persona ui-adapters explain --class-token ant-select --role combobox --project-root . --env dev
persona ui-adapters check --project-root . --env dev
make ui-adapter-check

Полный typed contract, precedence, diagnostics и client package example описаны в docs/ui-adapters.md. Исполняемый project pack находится в template/support/ui_adapters.py.

Artemis AMQP

UseArtemis предоставляет AMQP 1.0 transport для Apache ActiveMQ Artemis. persona.make(SendMessage(...)) отправляет bytes, строку или модель с зарегистрированным schema codec в address и ожидает broker settlement. persona.get(MessageInQueue(...)) читает одну доставку из queue или FQQN address::queue, подтверждает её и возвращает metadata, application properties, JSON envelope либо типизированную XSD/XML-модель через as_type.

Environment profile находится в skills.artemis.<name> и содержит url, auth_key, timeout, heartbeat, optional tls_ca_file и явный allow_insecure_auth для SASL через amqp://. Учётные данные хранятся в config/auth.yaml или environment resolver, а не в URL.

Agent knowledge и browser authoring / Agent knowledge and browser authoring

Project Profile поддерживает источники кода тестируемого приложения: Git URL и необязательную рабочую ветку для frontend, backend и микросервисов. Репозитории не скачиваются при project update/init/install/agent launch; on-demand lifecycle выполняется через persona project repos status|checkout|update, а Project Map анализирует код и записывает commit-bound выводы в Project Memory. Контракт описан в docs/tested-application-code-context.md.

RU: Любой запрос через make agent начинает навигацию с package-owned persona_knowledge(action="agent_flows"). Slash-команда уже подключает нужный skill и bounded route contract. Для точного route вызов persona_knowledge(action="agent_route", route="<route>") возвращает копируемые tool payloads, канонический Markdown state, current action, continuation/recovery и browser contract. Обычные project/file tools доступны для исходников и чтения возвращённых artifact paths.

Короткий eN ref текущего browser state передаётся как persona_browser(session_id=<session_id>, action=<action>, ref=<current_eN_ref>). find ищет текст, properties и semantic paths в сохранённом index; inspect возвращает точный узел, ancestry, table context и subtree без нового capture. persona_session_state восстанавливает единственное текущее состояние session. persona_generate_support(kind="element") принимает typed page/component/source/placement: текущий ref сохраняется как ref-free semantic fragment, выбранный внутренний узел поднимается до ближайшего однозначного владельца требуемой формы, а транзакция изменяет только указанное поле Page. page.output_path задаёт Python-файл, page.page_path задаёт browser route и используется только при генерации Page. Durable Page/Element/test code хранит semantic identity без ref. Native semantic observation является основным generation input; Rich snapshot API остаётся deprecated compatibility-входом на линейке 0.2.x.

Публичный Python/package contract:

  • distribution: persona-dsl
  • import package: persona_dsl
  • CLI: persona, persona-page-gen, persona-api-gen, persona-schema-gen, persona-mcp, persona-lsp
  • Version diagnostics: persona --version and persona-mcp --version
  • Agent bootstrap CLI: persona agent init, persona agent list-profiles, persona agent doctor

Persona Language Server

persona-lsp работает рядом с Pyright, Pylance или другим Python language server. Persona отвечает за framework diagnostics, completion, navigation, semantic rename, code actions, semantic presentation и безопасные generation transactions. Python companion отвечает за syntax, imports, typing, generic refactors и formatting. Сервер использует STDIO и стандартный LSP lifecycle.

persona-lsp --client-config all
persona-lsp --client-config vscode
persona-lsp --client-config qwen
persona lsp --client-config neovim
persona-lsp --project-root .

Typed profiles предусмотрены для VS Code, Neovim, Helix, Zed, Qwen Code CLI и GigaCode CLI. make install добавляет Persona в project-local .lsp.json и включает native LSP для Qwen/GigaCode независимо от MCP. Валидный .lsp.json объединяется по зарезервированному ключу persona с сохранением остальных серверов; некорректный файл заменяется канонической Persona-конфигурацией в той же транзакции. VS Code client собирается через make vscode-lsp-package; полный контракт описывает установку, trust, multi-root, recovery и поддерживаемые клиенты.

Проверка Persona-проекта / Persona Project Check

RU: persona check — packaged analyzer проекта, написанного на Persona, для before-merge проверки качества. Команда читает persona.check.yaml, применяет выбранный profile и возвращает агрегированный отчёт по стадиям. persona check не запускает authored scenarios, не строит Allure/runtime report UI и не очищает runtime outputs. Команда сохраняет machine-readable report в reports/persona-check/latest.json и human Markdown report в reports/persona-check/latest.md. Для interactive text runs команда печатает line-based progress по стадиям в stderr; --progress always|never управляет этим явно.

EN: persona check is the packaged before-merge project analyzer for projects written on Persona. It reads persona.check.yaml, applies the selected profile, and returns an aggregated staged report. persona check does not run authored scenarios, build the Allure/runtime report UI, or clean runtime outputs. It writes the machine-readable report to reports/persona-check/latest.json and the human Markdown report to reports/persona-check/latest.md. Interactive text runs print line-based stage progress to stderr; use --progress always|never to control it explicitly.

persona check --project-root . --profile merge
persona check --project-root . --profile strict --warnings-as-errors
persona check --project-root . --profile max
persona check --project-root . --stage scenario-metadata --stage secrets
persona check --project-root . --format json
persona check --project-root . --report-dir reports/persona-check
persona check --project-root . --progress always
persona check --list-stages

Исправления и форматирование Persona-проекта / Persona Project Fixing and Formatting

RU: persona fix применяет безопасные packaged автоисправления качества к проекту. Текущий safe-fix pipeline включает Ruff check --fix --no-cache и Black по существующим code roots scenarios, support и scripts. persona format оставлен как явный алиас formatter pipeline. Команды принимают --path для ограничения области и завершаются с non-zero exit code, если fixer/formatter недоступен или выбранный путь отсутствует.

EN: persona fix applies safe packaged quality autofixes to a project. The current safe-fix pipeline runs Ruff check --fix --no-cache and Black over the existing scenarios, support and scripts code roots. persona format remains an explicit formatter-pipeline alias. Use repeated --path values to restrict the scope. Commands exit non-zero when a fixer/formatter is unavailable or a selected path is missing.

persona fix
persona fix --path scenarios --path support/pages
persona format
persona format --path scenarios --path support/pages

Profiles:

  • advisory — Persona-semantic analyzer без delegated quality/security stages.
  • merge — default static gate для проекта перед merge.
  • strict — broad gate with warnings promoted to errors.
  • security — artifact hygiene, secrets-only scan, Ruff S security rules, dependency audit and optional local Semgrep SAST.
  • audit, max и public-template — broad packaged profiles for deeper review.

Project-local custom profiles are declared in persona.check.yaml under profiles.<name>. A custom profile extends a built-in or another custom profile and can set warnings_as_errors, max_console_diagnostics, excludes and stage overrides. The starter includes a project-max example profile that extends built-in max and promotes advisory Persona-quality findings to failures.

persona.check.yaml reference

RU: файл policy опционален. Если persona.check.yaml отсутствует, команда использует профиль merge. Корень YAML должен быть mapping; неизвестные ключи, неверные типы, неизвестный profile и custom profile inheritance cycle дают ошибку policy до запуска стадий.

EN: this is the public YAML reference for Persona project checks.

Порядок применения effective policy:

  1. выбранный built-in profile или profiles.<name>;
  2. inherited custom profile chain через extends;
  3. root-level stages, excludes, warnings_as_errors, max_console_diagnostics;
  4. CLI overrides: --profile, repeated --stage, --warnings-as-errors.

Root fields:

Field Type Default Meaning
profile non-empty string merge Built-in или custom profile, который выбирает набор стадий.
warnings_as_errors boolean false Promotes all warning diagnostics in the run to errors.
max_console_diagnostics positive integer selected profile default, usually 20 Caps console diagnostics. Saved JSON and Markdown reports keep full diagnostics.
excludes list of non-empty strings default source/cache excludes Extra fnmatch globs appended to default excludes for source collection.
profiles mapping {} Project-local named profiles under profiles.<name>.
stages mapping {} Root stage overrides applied after selected profile inheritance.

Custom profile fields under profiles.<name>:

Field Type Default Meaning
extends non-empty string merge Built-in or custom parent profile. Names must not override built-in profiles; cycles fail policy validation.
warnings_as_errors boolean inherited Promotes warnings for this profile.
max_console_diagnostics positive integer inherited Console diagnostic cap for this profile.
excludes list of non-empty strings inherited/default excludes Extra source globs appended before root excludes.
stages mapping inherited stages Per-stage overrides for this profile.

Stage fields under stages.<id> or profiles.<name>.stages.<id>:

Field Type Default Meaning
title non-empty string built-in title or stage id Human report title.
kind built-in or delegated inherited Built-in stage uses packaged analyzer code; delegated stage runs a command.
enabled boolean profile membership Selects the stage when no explicit --stage is passed.
required boolean inherited, usually true Delegated stages only. Unavailable or failing required commands fail the run; advisory delegated stages can skip or warn. Built-in stage failure is driven by diagnostics severity, and a built-in required override is rejected as invalid policy.
severity info, warning, error inherited Default severity for policy-controlled diagnostics emitted by that stage. Hard contract errors remain errors.
warnings_as_errors boolean inherited Promotes warnings only for this stage.
command shell-like string or list of strings built-in delegated command, if any Command for delegated stage. Unknown external stage ids must declare command.
args list of strings [] Extra arguments appended to command.
paths list of strings stage-specific Stage input roots for built-in stages and built-in delegated commands. Custom commands must include their path arguments in command or args.
thresholds mapping of string to non-negative integer stage-specific Numeric knobs read by built-in stages. Project-defined threshold keys are valid YAML, but packaged stages only act on the documented keys listed below.
max_diagnostics positive integer stage-specific or unlimited Caps console diagnostics for this stage. Saved JSON and Markdown reports keep full diagnostics.

Built-in profiles:

Profile Stages
advisory Persona semantic and hygiene stages without delegated quality/security stages.
merge format, ruff, mypy, Ruff S security rules, pip-audit, Vulture and all semantic/hygiene stages.
strict Same stages as merge, with stage warnings promoted to errors.
security artifact-hygiene, secrets, Ruff S security rules, pip-audit and optional Semgrep/Gitleaks/OSV stages.
audit Same stage set as merge plus optional Semgrep, Gitleaks, OSV, dependency hygiene, SBOM, license, shell, CI, Docker, Docker Compose and Markdown audit stages.
max Strongest packaged analyzer profile; projects can extend it with local requiredness and warning policy.
public-template Same stage set as merge; intended for public starter/template checks.

Built-in stage ids and stage-specific knobs:

Stage Checks Useful fields
project-shape Required Persona project paths and forbidden legacy paths. paths lists required project paths; default is config, scenarios, scenario_data, support.
artifact-hygiene Tracked env files, runtime outputs and cache artifacts. enabled, severity, max_diagnostics.
file-length Python file length in selected roots. paths; thresholds.max_lines; thresholds.warning_lines; severity.
importability Python source compile/importability check for maintained roots. paths, max_diagnostics.
complexity Function-level complexity policy for scenarios/support/scripts. paths; thresholds.max_complexity; thresholds.warning_complexity; severity; max_diagnostics.
strict-code Inline suppressions, broad typing escapes and forbidden legacy patterns. enabled, max_diagnostics.
duplicate-identities Duplicate scenario names, traceability ids and public support class names. severity, max_diagnostics.
duplicate-code Repeated Python code blocks in maintained project roots. thresholds.min_duplicate_lines; severity; max_diagnostics.
format python -m black --check over code roots. command, args, paths, required.
ruff python -m ruff check --no-cache over code roots. command, args, paths, required.
mypy python -m mypy, using pyproject.toml when present. command, args, paths, required.
security-code python -m ruff check --select S --ignore S101 --no-cache over project code roots. S101 is excluded because Persona scenarios use pytest-style assert as a supported observable check. command, args, paths, required.
dependency-audit Pip-audit of the installed virtual environment for pyproject.toml projects after make install; requirements-only projects are audited through their requirements files. command, args, required.
semgrep Optional external Semgrep SAST through project-pinned local rules. Persona does not install Semgrep into the audited project environment. Default discovery uses semgrep.yml, semgrep.yaml, .semgrep.yml, .semgrep.yaml, rules/semgrep or semgrep-rules; use command for another reviewed executable/rules path. command, args, required; default required: false.
gitleaks Optional Gitleaks repository secret scan. command, args, required; default required: false.
osv-audit Optional OSV dependency vulnerability audit. command, args, required; default required: false.
dependency-hygiene Optional dependency/import hygiene through deptry. command, args, required; default required: false.
sbom Optional CycloneDX SBOM generation. command, args, required; default required: false.
license-audit Optional license report through pip-licenses. command, args, required; default required: false.
dead-code Vulture dead-code scan for support/scripts; advisory by default. command, args, required; default required: false.
suite-topology __suite__.py presence, shape and supported suite(...) keywords. enabled, max_diagnostics.
scenario-metadata Required @title, @story, @tag; traceability advisory metadata. thresholds.traceability_warnings; severity; max_diagnostics. Set traceability_warnings: 0 to disable owner/severity/id advisories.
scenario-body-quality Sleep calls are hard errors; unasserted persona.get, formal/no-op checks, missing observable checks, missing readiness chain and long raw Ops flows are advisory by default and can fail under strict or warnings_as_errors. thresholds.raw_ops_warning; thresholds.readiness_ops_warning; severity; warnings_as_errors; max_diagnostics.
support-quality Persona discovery diagnostics for maintained support/page objects. severity, max_diagnostics.
data-config YAML/JSON/TOML/CSV parse checks under config and scenario_data. enabled, max_diagnostics.
generated-contracts Python compilation for support/contracts. enabled, max_diagnostics.
reference-integrity Static lifecycle/retry/resource/scenario-data/config/upload file reference checks from suite and scenario metadata. severity, max_diagnostics.
secrets Credentials, tokens, private keys, real env/auth files and secret-like assignments. enabled, max_diagnostics; branding and organization names are not findings.
shellcheck Optional shell script lint. command, args, required; default required: false.
actionlint Optional GitHub Actions workflow lint. command, args, required; default required: false.
hadolint Optional Dockerfile lint. command, args, required; default required: false.
compose-config Optional Docker Compose config validation. command, args, required; default required: false.
markdownlint Optional Markdown lint. command, args, required; default required: false.

Example maximum project profile:

profile: merge

profiles:
  project-max:
    extends: max
    warnings_as_errors: true
    max_console_diagnostics: 80
    stages:
      complexity:
        severity: error
        thresholds:
          max_complexity: 10
          warning_complexity: 6
      scenario-metadata:
        severity: error
        max_diagnostics: 80
      scenario-body-quality:
        severity: error
        max_diagnostics: 80
      support-quality:
        severity: error
        max_diagnostics: 80
      dead-code:
        required: true
      semgrep:
        required: true
        command:
          - semgrep
          - scan
          - --config
          - rules/semgrep
          - --quiet
          - .
      gitleaks:
        required: true
      osv-audit:
        required: true
      dependency-hygiene:
        required: true
      sbom:
        required: false
      license-audit:
        required: false
      shellcheck:
        required: false
      actionlint:
        required: false
      hadolint:
        required: false
      compose-config:
        required: false
      markdownlint:
        required: false

Example advisory external stage:

profiles:
  security-local:
    extends: security
    stages:
      external-sca:
        title: External SCA
        kind: delegated
        command:
          - python
          - -m
          - pip_audit
        required: false

Consolidated report shape

RU: text report сначала показывает semantic summary, затем сводку по стадиям, диагностические блоки по стадиям и финальную строку Summary. Каждая диагностика содержит stable PCS-... code и machine-readable reason. max_console_diagnostics ограничивает только console output. persona check сохраняет полный machine-readable report в reports/persona-check/latest.json и полный human Markdown report в reports/persona-check/latest.md. Для CI используйте --format json. В интерактивном text-терминале live progress показывает обновляемую строку активной стадии в stderr; в non-TTY text runs и при --progress always progress печатается отдельными строками: [i/N] START <stage> и [i/N] PASS|WARN|FAIL|SKIP <stage> (...). При --format json default auto progress выключен, чтобы stdout оставался валидным JSON.

Для исправления diagnostics агенту следует опираться на machine-readable code, reason, stage_id, path, line и полный reports/persona-check/latest.json. Локализованный message является человеческим пояснением, а не единственным repair contract.

EN: text output starts with semantic summary, then grouped stages, diagnostic blocks and the final summary line. Interactive text terminals render the active stage as an updating stderr line; non-TTY text runs and --progress always write line-based stage events. --format json keeps stdout valid JSON. The command also writes full JSON and Markdown reports under reports/persona-check/. Agents should use JSON fields such as code, reason, stage_id, path, line and semantic_summary for remediation; localized console messages are human explanations.

Persona check: profile=strict status=failed
Project: /workspace/example-project

Semantic summary:
  project: scenarios=42 modules=18 suites=9 support=31
  quality: direct_ops=14 raw_scenarios=3 missing_checks=1
  domains: checkout=18, accounts=12, admin=8, root=4
  suites: Root / Checkout=18, Root / Accounts=12, Root / Admin=8, Root=4
  support: shared=4 domain_owned=23 top=support.steps.login=8, support.facts.account=6, support.expectations.order=5
  metadata: title=100.0%, story=100.0%, tag=97.62%, severity=90.48%, owner=76.19%, identity=83.33%
  references: lifecycle_profiles: declared=4, used=3, missing=0; retry_profiles: declared=2, used=2, missing=0; resources: declared=5, used=4, missing=1; data_files: declared=0, used=3, missing=0; config_paths: declared=0, used=1, missing=0; files: declared=0, used=2, missing=0
  decision: profile=strict status=failed; failing stages: reference-integrity, scenario-metadata, scenario-body-quality

Stages:
  [PASS] project-shape (4 ms, errors=0 warnings=0 info=0)
  [PASS] artifact-hygiene (12 ms, errors=0 warnings=0 info=0)
  [PASS] importability (10 ms, errors=0 warnings=0 info=0)
  [WARN] complexity (17 ms, errors=0 warnings=2 info=0)
  [PASS] format (180 ms, errors=0 warnings=0 info=0)
  [PASS] ruff (145 ms, errors=0 warnings=0 info=0)
  [PASS] mypy (920 ms, errors=0 warnings=0 info=0)
  [FAIL] reference-integrity (11 ms, errors=1 warnings=0 info=0)
  [FAIL] scenario-metadata (32 ms, errors=3 warnings=0 info=0)
  [FAIL] scenario-body-quality (28 ms, errors=1 warnings=0 info=0)
  [PASS] secrets (35 ms, errors=0 warnings=0 info=0)

scenario-metadata: diagnostics
  - error scenarios/checkout/test_checkout.py:42 PCS-MET-004 missing-owner: Сценарий должен иметь owner label для владения.
  - error scenarios/checkout/test_checkout.py:42 PCS-MET-006 missing-id: Сценарий должен иметь id/link/issue/testcase для трассировки.
  - error scenarios/checkout/test_checkout.py:42 PCS-MET-005 missing-severity: Сценарий должен иметь severity для приоритета triage.

scenario-body-quality: diagnostics
  - error scenarios/checkout/test_checkout.py:58 PCS-BDY-006 raw-ops-flow: Сценарий содержит длинную цепочку прямых Ops; для поддерживаемого production flow лучше вынести поток в Step/CombinedStep/Expectation.

reference-integrity: diagnostics
  - error scenarios/checkout/test_checkout.py:42 PCS-REF-003 missing-resource: Resource не найден: checkout.account.

Summary: status=failed exit_code=1 duration=1356 ms

JSON report has stable machine-readable keys:

{
  "profile": "strict",
  "project_root": "/workspace/example-project",
  "status": "failed",
  "exit_code": 1,
  "counts": {
    "severity": {"info": 0, "warning": 2, "error": 5},
    "status": {"passed": 8, "warning": 1, "failed": 3, "skipped": 0}
  },
  "excludes": ["reports/**", "artifacts/**"],
  "semantic_summary": {
    "project": {
      "scenarios_total": 42,
      "test_modules_total": 18,
      "suites_total": 9,
      "support_modules_total": 31
    },
    "metadata_coverage": {
      "title": {"present": 42, "missing": 0, "percent": 100.0},
      "story": {"present": 42, "missing": 0, "percent": 100.0},
      "tag": {"present": 41, "missing": 1, "percent": 97.62},
      "severity": {"present": 38, "missing": 4, "percent": 90.48},
      "owner": {"present": 32, "missing": 10, "percent": 76.19},
      "identity": {"present": 35, "missing": 7, "percent": 83.33}
    },
    "scenario_quality": {
      "direct_ops_total": 14,
      "scenarios_with_raw_ops": 3,
      "scenarios_missing_observable_check": 1,
      "readiness_calls_total": 6,
      "formal_checks_total": 1
    },
    "domains": {"checkout": 18, "accounts": 12, "admin": 8, "root": 4},
    "suites": {"Root / Checkout": 18, "Root / Accounts": 12, "Root / Admin": 8, "Root": 4},
    "support": {
      "layers": {"pages": 6, "steps": 10, "expectations": 5, "shared": 4},
      "shared_modules": 4,
      "domain_owned_modules": 23,
      "top_reused_modules": [
        {"module": "support.steps.login", "usages": 8}
      ]
    },
    "references": {
      "lifecycle_profiles": {"declared": 4, "used": 3, "missing": []},
      "retry_profiles": {"declared": 2, "used": 2, "missing": []},
      "resources": {"declared": 5, "used": 4, "missing": ["checkout.account"]},
      "data_files": {"declared": 0, "used": 3, "missing": []},
      "config_paths": {"declared": 0, "used": 1, "missing": []},
      "files": {"declared": 0, "used": 2, "missing": []}
    },
    "top_risky_files": [
      {"path": "scenarios/checkout/test_checkout.py", "score": 7, "errors": 1, "warnings": 1, "info": 0}
    ]
  },
  "stages": [
    {
      "id": "scenario-metadata",
      "title": "Scenario metadata",
      "status": "failed",
      "duration_ms": 32,
      "counts": {"info": 0, "warning": 0, "error": 3},
      "diagnostics": [
        {
          "stage_id": "scenario-metadata",
          "severity": "error",
          "code": "PCS-MET-004",
          "message": "Сценарий должен иметь owner label для владения.",
          "reason": "missing-owner",
          "path": "scenarios/checkout/test_checkout.py",
          "line": 42
        }
      ]
    }
  ]
}

Built-in stages cover project shape, tracked artifact hygiene, importability, complexity, strict code policy, duplicate identities, duplicate code, suite topology, effective scenario metadata through suite tree, scenario body quality, support quality diagnostics, data/config parsing, generated contracts, reference integrity and secrets-only scanning. Delegated stages run Black, Ruff, Mypy, Ruff S security rules, pip-audit, Vulture, optional audit tools or configured external commands through policy.

format, ruff, mypy, security and maintainability delegated stages inspect maintained human-authored roots. Generated API/XSD/JSON/WSDL modules under support/contracts are owned by generated-contracts; project initialization and update add a scoped Mypy override for support.contracts without weakening type checking of scenarios or maintained support code.

Privacy contract: default scan fails credentials, tokens, private keys, real env or auth files and secret-like literal assignments. Organization names, product names and normal project branding are not default findings.

Локальный Runner / Local Runner

RU: persona run, persona launch ... и make-цели starter-проекта пишут выходной слой запуска в reports/<env>/<launch_id>/, artifacts/<env>/<launch_id>/ и reports/latest/.

EN: persona run, persona launch ..., and starter Make targets write launch outputs to reports/<env>/<launch_id>/, artifacts/<env>/<launch_id>/, and reports/latest/.

RU: persona report info --project-root <project> --env <env> --launch-id <launch_id> читает summary.json и journal.jsonl. Для failed launch команда печатает Ошибки сценариев: work item, название, Место ошибки в формате path:line[:column] function, тип и сообщение исключения, фрагмент пользовательского стека, а также ссылки на traceback, runtime log, stdout и stderr artifacts. JSON-режим отдаёт те же данные в failed_items[].failure_diagnostics.

EN: persona report info --project-root <project> --env <env> --launch-id <launch_id> reads summary.json and journal.jsonl. For a failed launch, it prints Ошибки сценариев: work item, title, Место ошибки as path:line[:column] function, exception type and message, user stack excerpt, and links to traceback, runtime log, stdout, and stderr artifacts. JSON mode returns the same data in failed_items[].failure_diagnostics.

RU: persona.make(...), yield-операции внутри Step и persona.check(actual, expectation) формируют вложенные шаги canonical report и Allure projection. При окончательном падении сценария runner прикладывает failure-page.html и failure-page.png для активной страницы каждого уже загруженного browser skill. Перед чтением HTML runner обновляет Persona Runtime snapshot, поэтому актуальные элементы получают свежие data-persona-id. Если runtime refresh недоступен, сохраняется raw DOM без маскирования исходной ошибки. Сбор выполняется после исчерпания test-level retry и управляется reporting.enabled, reporting.pagesource_on_fail и reporting.screenshot_on_fail; явное false отключает соответствующий артефакт.

EN: persona.make(...), yielded operations inside a Step, and persona.check(actual, expectation) produce nested canonical report steps and Allure projection entries. On a terminal scenario failure, the runner attaches failure-page.html and failure-page.png for the active page of every already loaded browser skill. Before reading HTML, the runner refreshes the Persona Runtime snapshot so current elements receive fresh data-persona-id values. If runtime refresh is unavailable, raw DOM is still captured without masking the original failure. Capture runs after test-level retries are exhausted and is controlled by reporting.enabled, reporting.pagesource_on_fail, and reporting.screenshot_on_fail; explicit false disables the corresponding artifact.

RU: wait_until(..., description="Ожидание статуса READY во внешнем API") использует переданный текст как полный заголовок canonical/Allure шага, runtime events и диагностики таймаута. Значение None сохраняет заголовок по имени класса expectation. Вложенный шаг Получено значение: ... и поле step_end.result содержат полное строковое представление результата без ограничения длины.

EN: wait_until(..., description="Wait for READY status in the external API") uses the supplied text as the complete canonical/Allure step title, runtime event description, and timeout diagnostic. None keeps the expectation class name title. The nested Received value: ... equivalent and step_end.result retain the complete string representation without a length cap.

Генераторы контрактов

Persona генерирует committed contract packages для проекта:

  • persona-page-gen — page object из browser/runtime snapshot.
  • persona-api-gen — OpenAPI API package с Pydantic models, builders, Ops, responses и catalog.
  • persona-schema-gen xsd — XSD/XML package с models, builders и schema metadata.
  • persona-schema-gen json — JSON Object Pydantic package из JSON Schema или явно выбранного sample JSON.
  • persona-schema-gen wsdl — WSDL/SOAP package с models, builders, service/port/operation catalog и generated SOAP Ops.

RU: Page generation сохраняет atomic semantic controls с ARIA role/name как Button/Link/Checkbox/Switch/Radio/Tab(accessible_name=...); общий component test_id используется как stable key вместе с семантическим ключом, scoped owner или index. Snapshot ref остаётся временной координатой только внутри Persona MCP browser session; готовый Page/Element связывается через semantic identity и Page.element_path и не хранит ref. Heading/accordion wrapper с единственным одноимённым Link/Button child генерируется как action-field на owner level. Безымянные list/listitem wrappers наследуют semantic hint от единственного содержательного child: навигация, breadcrumb и pagination получают executable ids вроде tips, home, page_1, next, tools_list, а не numeric wrapper class names. Common chrome (Header/Sidebar/Footer, Banner, Navigation, ContentInfo) извлекается или переиспользуется как page component из support/pages; для page-specific generation используется explicit target scope вместо копирования всего сайта в один PageObject. Повторяющиеся product/card/tile/item контейнеры с пользовательскими полями и действиями генерируются как composite Repeated коллекции. Прототип содержит стабильные поля вроде product_image, price, product_name, add_to_cart, view_product; item_scope связывает контейнер с уникальным semantic descendant через repeated_item_scope(ancestors=...). Генератор сохраняет структурную глубину схлопнутых layout-обёрток, а runtime refs, CSS structural classes, item-specific URLs и глобальные индексы не попадают в прототип. ElementList, Repeated, Table.rows, Table.body_rows и Table.headers являются ленивыми locator contracts, а не Python sequences. Прямая итерация через for, enumerate, list и comprehensions отклоняется до browser-вызова. Bounded traversal получает размер через persona.get(ElementsCount(collection)) и обращается к collection.nth(index) внутри range(count). Значения столбца читаются одним persona.get(TableColumnData(table, column)).

Один Page Element может адресовать конкретное совпадение общего semantic locator без второго поля страницы. Методы возвращают копию того же типа и не изменяют объявленный Page Element:

persona.make(Click(page.action.first()))
persona.make(Click(page.action.nth(1)))
persona.make(Click(page.action.last()))

nth(index) использует zero-based индекс; отрицательные индексы соответствуют Playwright locator contract. Выбранный Element поддерживается всеми Ops и Facts, которые принимают обычный Page Element.

Native <select multiple>, ARIA multiple listbox/combobox и Ant/UiKit multiple select моделируются через Page-owned MultiSelect. Сценарий задаёт точный набор через persona.make(SelectMultipleOptions(page.tags, values)), читает состояние через persona.get(MultiSelectValues(page.tags)) и очищает control через ClearTypedControl. Методы Page element select, add, remove, clear и selected_values остаются typed runtime для собственных Ops. Они используют полное совпадение option label, связанный popup и наблюдаемое selected-состояние. Если popup содержит одинаковые label, обычное строковое значение возвращает диагностику неоднозначности. Явный MultiSelectChoice(label="316-033-1-1", occurrence=1) выбирает ordinal среди точных совпадений; SelectOption(page.tags, index=2) выбирает option по DOM-индексу внутри связанного popup, включая Ant portal. Для виртуализированного Ant/UiKit select связь aria-controls адресует popup через служебный listbox, кликабельные options принадлежат virtual list, а выбранный label читается из содержимого chip независимо от его comment-title. Точное совпадение option разрешается непосредственно перед кликом: вставка, удаление или перерисовка посторонних virtual-list options не сдвигает выбранный label на другой DOM-элемент. Успешные select и add закрывают связанный Ant/UiKit popup через keyboard owner и ожидают его скрытия. Открытие соседнего MultiSelect сначала закрывает точно связанный видимый popup, поэтому portal не перехватывает следующий control. Поисковый ввод внутри открытого popup выполняется через persona.make(Fill(page.tags.control, query)): control разрешается в единственный adapter-owned editable target. Декларативные действия popup, например page.tags.popup.select_all, разрешаются от полного popup owner, связанного с MultiSelect через aria-controls/aria-owns; кнопки рядом со служебным listbox доступны без DOM-привязки portal к Page owner. Page generator распознаёт multiple, aria-multiselectable=true и Ant/UiKit multiple class markers и генерирует Page-owned MultiSelect со штатной semantic identity (label, accessible name, test id, HTML name или placeholder). DOM-селекторы компонента остаются внутри UI adapter и не попадают в generated Page. Полный подтверждённый набор до 50 options материализуется как variants; неполный, виртуализированный или большой набор остаётся runtime-driven и сопровождается typed diagnostic. Native date, datetime-local, time и Ant Design picker моделируются через Page-owned DatePicker, DateTimePicker, DateRangePicker и TimePicker. Сценарий вызывает SelectDate, SelectDateTime, SelectDateRange и SelectTime через persona.make, а значения читает через persona.get(PickerValue(...)) или persona.get(DateRangeValues(...)). Операции принимают date/datetime/time либо канонические ISO-строки, выбирают точную календарную ячейку или time-column value и ожидают наблюдаемое значение input. Generator сохраняет picker одним полем Page и исключает календарный popup и его ячейки из PageObject. После генерации поддерживаемый PageObject проходит refactor pass и доводится до доменной структуры: classes используют PascalCase, Python fields/methods и Page/Element public metadata разделены. Python fields/methods используют readable English snake_case, protocol keys остаются английскими. Page class, PageDefinition.class_name и element field не локализуются, не заполняются русским описанием и не записываются транслитом; у Page/Element нет public name, а русское доменное описание страницы или элемента заполняется через Page/Element description, report label или другой human metadata. При пустом Element description runtime использует Python field alias только как display label для отчётов и диагностики; locator contract остаётся в accessible_name, text, label, placeholder, test_id, locator, html_name, title, url, alt_text и связанных selector-полях. Static persona check сообщает missing_element_description (PCS-SUP-005) как support-quality warning. Если Element задаёт literal text и literal variants, static persona check сообщает element_text_not_in_variants (PCS-SUP-020), когда text не входит в список variants; runtime импорт PageObject не останавливается, а явный выбор через by_variant(...)/get_option(...) остаётся строгим. При refactor pass поля с одинаковым effective role в одном owner scope и пересекающимся accessible_name, например Пароль / Новый пароль, получают exact=True; полностью одинаковые role/name matches требуют более узкий owner/locator или index, потому что exact=True их не различает. Custom element subclasses наследуют role от доказанного Persona base class (TextField, Button, ...); если role не доказана, locator-quality не выдаёт overlap warning. Plain visible message описывается как Text(text=..., exact=True), а Status(accessible_name=...) используется только для подтверждённого ARIA status node. Region/Main/Dialog boundaries опираются на реальный DOM/ARIA owner, locator, test_id или структурную семантику; heading text сам по себе остаётся child element.

EN: Page generation keeps atomic semantic controls with ARIA role/name as Button/Link/Checkbox/Switch/Radio/Tab(accessible_name=...); a shared component test_id is stable with a semantic key, scoped owner, or index, and runtime resolution uses stable semantic or structural Page contracts. Snapshot refs are temporary coordinates inside one Persona MCP browser session and are never persisted in a ready Page/Element. Heading/accordion wrappers with one same-name Link/Button child are generated as owner-level action fields. Unnamed list/listitem wrappers inherit a semantic hint from the single meaningful child: navigation, breadcrumb and pagination generate executable ids such as tips, home, page_1, next, tools_list, not numeric wrapper class names. Common chrome (Header/Sidebar/Footer, Banner, Navigation, ContentInfo) is extracted or reused as a page component from support/pages; page-specific generation uses an explicit target scope instead of copying the whole site into one PageObject. Repeated product/card/tile/item containers with user-facing fields and actions generate composite Repeated collections with stable child fields such as product_image, price, product_name, add_to_cart and view_product. The generated item_scope connects the item container to one unique semantic descendant through repeated_item_scope(ancestors=...), preserving structural depth without persisting snapshot refs or structural CSS classes. After generation, maintained PageObjects go through a refactor pass and are refined into domain structure: classes use PascalCase, Python fields/methods and Page/Element public metadata are separated. Python fields/methods use readable English snake_case, protocol keys stay English. Page class, PageDefinition.class_name and element fields are not localized and are not transliterated; Page/Element has no public name, and localized domain wording goes into Page/Element description, report label or other human metadata. Empty Element description uses the Python field alias only as a runtime display label for reports and diagnostics; locator semantics stay in explicit selector fields, and static persona check reports missing_element_description (PCS-SUP-005) as a support-quality warning. When an Element declares literal text and literal variants, static persona check reports element_text_not_in_variants (PCS-SUP-020) if text is outside the variants list; PageObject import remains runtime-safe, while explicit by_variant(...)/get_option(...) selection stays strict. During the refactor pass, same effective-role fields in the same owner scope with substring-overlapping accessible_name values such as Password / New password get exact=True; equal role/name matches require a narrower owner/locator or index because exact=True cannot distinguish them. Custom element subclasses inherit role from a proven Persona base class (TextField, Button, ...); when the role is not proven, locator-quality does not emit an overlap warning. Plain visible messages are modeled as Text(text=..., exact=True), while Status(accessible_name=...) is reserved for a confirmed ARIA status node. Region/Main/Dialog boundaries use a real DOM/ARIA owner, locator, test_id, or structural semantics; heading text remains a child element by itself.

RU: Web expectations проверяют составные UI-контролы через их семантические targets. ToBeEnabled/ToBeDisabled читают состояние native и Ant/UiKit Select, а ToBeClickable проверяет enabled, visibility, stability и получение pointer events без выполнения клика. Видимое отключённое поле проверяется композицией BeVisible(), ToBeDisabled(), визуально отсутствующее поле — WaitForElementState(element, "hidden"); удалённый DOM-узел имеет состояние detached.

EN: Web expectations evaluate composite controls through semantic targets. ToBeEnabled/ToBeDisabled read native and Ant/UiKit Select state, while ToBeClickable verifies enabled state, visibility, stability, and pointer-event reception without clicking. Use BeVisible(), ToBeDisabled() for a visible disabled field, WaitForElementState(element, "hidden") for a visually absent field, and detached for a removed DOM node.

Автоматическая готовность UI-действий

UI-действия работают с ленивыми Playwright locator и сами ожидают готовность целевого элемента. Structural Table, TableRow, TableCell, ColumnHeader, indexed Select, relative_to(...) и текущий browser ref сначала ожидают адресуемый DOM-узел, затем действие использует стандартную Playwright actionability. PressKey ожидает видимый target, UploadFile — прикреплённый file input. Selection и expansion таблицы ожидают соответствующий checkbox или expander.

Adapter-resolved Select, MultiSelect, picker, Table, Dropdown и project components используют тот же контракт: registry ожидает lazy candidate среди ближайших совместимых adapters и после появления повторяет полный DOM/identity match. Popup, option, editable control, fixed header и другие внутренние target ожидает operation runtime выбранного adapter.

timeout действия применяется и к structural/semantic resolve, и к самому Playwright-действию. Ошибка resolve содержит тип и описание target, structural координаты и ожидаемый UI-контракт. Отдельный WaitFor* перед тем же действием не нужен только ради появления его target.

Явное ожидание остаётся частью сценария, когда требуется самостоятельный наблюдаемый сигнал: navigation/load state, popup или новая вкладка, network response, завершение загрузки доменных данных, изменение атрибута либо другое состояние, которое нельзя вывести из actionability целевого элемента. force=True сохраняет Playwright-семантику и осознанно обходит часть проверок actionability, но не structural/semantic resolve.

Конфигурация окружения / Environment Configuration

Persona автоматически определяет ОС процесса: win32 использует platforms.windows, linuxplatforms.linux, darwinplatforms.macos. Параметр платформы в CLI и переменная PERSONA_PLATFORM отсутствуют. Если блок текущей ОС не объявлен, действует базовый YAML.

Persona detects the process OS automatically: win32 uses platforms.windows, linux uses platforms.linux, and darwin uses platforms.macos. There is no platform CLI option or PERSONA_PLATFORM. An omitted current-platform block keeps the base YAML.

persona:
  base-url: "https://example.test"

skills:
  browser:
    default:
      base-url: "${persona.base-url}"
      type: "chromium"

platforms:
  windows:
    skills:
      browser:
        default:
          channel: "msedge"
  linux:
    skills:
      browser:
        default:
          type: "chromium"
  macos:
    skills:
      browser:
        default:
          channel: "chrome"

Окружение config/{env}.yaml выбирается в порядке: явный --env, process PERSONA_ENV, PERSONA_ENV из общего .env, [tool.persona].default_env. Значения свойств имеют приоритет: process environment → .env.{env} → общий .env → platform overlay → базовый YAML. Dotenv-файлы читаются отдельно для каждого Config и не изменяют глобальный os.environ.

The environment selector order is explicit --env, process PERSONA_ENV, common .env PERSONA_ENV, then [tool.persona].default_env. Property precedence is process environment, .env.{env}, common .env, the platform overlay, then base YAML. Dotenv files are scoped to each Config and never mutate global os.environ.

Имена свойств используют relaxed binding: точки, дефисы и подчёркивания преобразуются в одно подчёркивание, повторяющиеся разделители сворачиваются, регистр переводится в верхний. Поэтому persona.base-url, persona.base_url и persona.base.url соответствуют PERSONA_BASE_URL; skills.browser.default.base-url соответствует SKILLS_BROWSER_DEFAULT_BASE_URL. Env override применяется только к существующему canonical property. Коллизия canonical имён является ошибкой.

Property names use relaxed binding: dots, hyphens, and underscores become one underscore, repeated separators collapse, and letters become uppercase. Therefore persona.base-url, persona.base_url, and persona.base.url map to PERSONA_BASE_URL, while skills.browser.default.base-url maps to SKILLS_BROWSER_DEFAULT_BASE_URL. Environment overrides apply only to an existing canonical property; canonical collisions are errors.

PERSONA_ENV=dev
PERSONA_BASE_URL=https://stage.example.test
SKILLS_BROWSER_DEFAULT_BASE_URL=https://browser.example.test
SKILLS_BROWSER_DEFAULT_HEADLESS=false

Корневые группы persona, service, project и другие custom property groups допустимы, если хотя бы одно их свойство используется через ${...}. Точная ссылка сохраняет тип; ссылка внутри строки принимает scalar. Env scalars читаются как YAML, списки — только как JSON arrays. Ссылки, циклы, типы, дубликаты и коллизии диагностируются с файлом, строкой, столбцом и property path. YAML-наследование extends не используется.

Custom root groups such as persona, service, and project are valid when at least one property is consumed through ${...}. An exact reference preserves its type, while string interpolation accepts scalars. Environment scalars use YAML parsing and lists require JSON arrays. Reference, cycle, type, duplicate, and collision errors include file, line, column, and property path. There is no YAML extends inheritance.

config/{env}.yaml поддерживает batch generation documents:

  • generator.api.documents[]
  • generator.json.documents[]
  • generator.xsd.documents[]
  • generator.soap.documents[]

XSD document задаёт корневую схему, output routing и необязательные XML prefixes:

generator:
  xsd:
    output_root: "support/contracts"
    documents:
      - name: "arrow_guides"
        schema: "scenario_data/schemas/ArrowGuides.xsd"
        package: "support.contracts.arrow_guides"
        namespace_prefixes:
          ns2: "urn:example:arrow-guides"

Генерация выполняется командой persona-schema-gen xsd --xsd-document arrow_guides --project-root .. namespace_prefixes управляет только написанием XML prefix. Namespace элементов определяется XSD: импортированная схема без targetNamespace остаётся no-namespace, а chameleon xs:include наследует namespace включающей схемы. Generated codec проверяет XML через локальный XSD bundle и явно отклоняет schema и payload с DOCTYPE.

MCP authoring surface использует единый Persona runtime:

  • MCP tools/call возвращает в content[0].text самодостаточный предметный результат: outcome, текущее состояние, diagnostics, точные следующие действия, recovery и переход. structuredContent сериализует тот же контракт для машинной обработки. Большие snapshot/history artifacts доступны по возвращённым путям через обычные файловые инструменты и MCP detail routes.
  • persona_knowledge читает compact guide, guide_search, framework catalog и config catalog; include_examples=true добавляет package-owned examples выбранной темы или entity. Guide details/examples, search results, constructor properties, public methods и config fields всегда возвращаются server-owned страницами; продолжение выполняется только через returned next_page/next_pages и точные topic_index_offset, details_offset, examples_offset, constructor_offset, methods_offset, fields_offset или search offset. framework_search.invocation_modes выбирает symbols, которые поддерживают хотя бы один указанный live command mode; для web Ops используется точный query, затем returned entity route.
  • persona_knowledge(action="agent_problem_resolution") возвращает единый рабочий цикл основного агента, primary roles и subagents: перечитать активный packet, получить project profile, пройти от memory record к source refs и code repositories, выбрать релевантные retrieval/project/Knowledge/domain/runtime источники, задать один вопрос пользователю и сохранить ответ. Task-local open question не является gap; evidence-backed gap или отдельная внешняя задача появляются только в финальной агрегации нерешённого остатка.
  • persona_project читает inventory/search/entity/lifecycle/retry данные текущего project-root и обновляет discovery cache при изменении файлов. inventory(include_ids=true, limit=N, filters={...}) возвращает bounded key id previews, totals и omitted counts; filters сужают key ids и facet_counts previews без изменения full summary. domain_support_map в inventory является compact overview с layers/status counts/totals/omitted and paged domains; domain_support_domains_limit/domain_support_domains_offset управляют страницей доменов и возвращают domains_total/domains_omitted/domains_offset; include_domain_support_details=true и domain_support_limit=N добавляют bounded details от 0 до 10 для small review. diagnostics_limit=N управляет inventory diagnostics preview от 0 до 25 и возвращает diagnostics_total/diagnostics_omitted; search(filters={support_domains, support_layers, support_statuses}, limit, offset) используется для paged domain/layer/status drill-down; search(include_ids=true) добавляет returned match_entity_ids; search/entity(include_related=true) возвращают bounded related preview с related_total/related_omitted; search/entity используются для точных сущностей и scoped diagnostics. Page entity возвращает page_ref и page_element_ref на nested elements для typed operation args. Scenario entity возвращает bounded executable outline с imports, persona call sequence и referenced page/component ids; generated API operation entity возвращает constructor_signature, constructor_parameters, response_contract и usage_examples. Diagnostics с context=support_quality и severity=warning подсвечивают PageObject/support ids, требующие refactor: localized/transliterated Page class names, Step/CombinedStep/Goal and reusable page-component class names, transliteration, numeric/generic/value-derived/overlong fields, missing Page/Element description for generated/refactor-needed support, same-role/same-scope accessible_name overlap без exact=True, equal role/name matches без scope/index, plain-message Status(accessible_name=...) без DOM anchor и label-only owner boundaries. suggested_identifier_kind может быть page_class, python_field или component_class; suggestion является review candidate, а не автоматическим rename. EN: scenario and API operation entities expose authoring-critical structure without opening project source files first; support_quality diagnostics mark generated support that must be refactored before production authoring.
  • persona_retrieval объединяет package core knowledge и discovery corpus текущего проекта. mode=auto|hybrid может использовать lexical ranking; structured и compact ответы явно сообщают effective_mode и semantic_provider с CSS configured/used/status и фактическими model/dimension из query embedding response. mode=semantic возвращает только semantic-ranked entries либо effective_mode=semantic_unavailable с пустым entries, bounded diagnostics и next_action. Project index обновляется через action=refresh, scope=project, а action=wait, scope=project, wait_timeout_seconds=1..20 возвращает текущую фазу и числовой прогресс job без остановки фоновой сборки по истечении bounded wait. Core index является package data и обновляется официальной knowledge/package сборкой. .persona/** не входит в project discovery corpus, поэтому local runtime и retrieval artifacts не делают собственный index stale. EN: retrieval responses explicitly expose the effective mode and actual CSS provider metadata, semantic mode never substitutes lexical entries, project rebuild jobs expose bounded waits and progress, and the core index is immutable package data.
  • persona_project_memory управляет памятью проекта: action=status|ingest|remember|recall|context|assess|retire|delete, typed records с memory_type=semantic|episodic|procedural, evidence refs, validity window, supersede/conflict links, context packs, source/evidence packs and test sufficiency assessment. Agent-facing recall/context по умолчанию возвращают только active records со статусами accepted|open; proposed|rejected|superseded|resolved доступны только при явном include_inactive=true для аудита. Ошибочные или устаревшие записи переводятся через action=retire в rejected|superseded|resolved с обязательным reason; action=delete является hard-delete для явно выбранных record_ids и также требует reason. [tool.persona.project_memory].provider = "local" использует reviewed audit mirror .persona/project_memory/memory.jsonl; provider = "cognee" подключает optional Cognee library backend под .persona/project_memory/cognee без отдельного MCP server. Источники Jira/Confluence/repo/Persona inventory/run/session ingest-ятся как source evidence с content hash и parent/child refs, а не становятся памятью сами по себе. Context/source/evidence packs доступны через MCP resources persona-memory://..., включая persona-memory://sources and persona-memory://context/<context_pack_id>. Human-facing views генерируются вне MCP через persona memory view, persona memory render или Make targets; HTML graph viewer строит memory/kind/topic/source anchors из records, tags and source audit tree. EN: persona_project_memory stores verified active project memory records, keeps inactive audit records out of default agent context, and returns task-specific context packs instead of making the agent reinterpret raw sources on every task.
  • persona_generate_support(page|element) принимает канонический typed payload с page, source и, для element, component/placement. page.description записывает Page description, component.description записывает описание выбранного field. page.output_path является project-relative Python path, page.page_path является browser route/URL и не принимается для element update. component.output_path используется только для action="extract". source.snapshot_path читает persisted RichAriaSnapshot artifact внутри project-root через RichAriaSnapshot.from_yaml_file, а не через raw yaml.safe_load. Python-only поля wait_for_element, wait_for_element_state и wait_for_element_timeout относятся к GeneratePageObject, а не к persona_generate_support.
  • persona_session_open по умолчанию входит в единственную подходящую live session той же task_id; new_session=true создаёт отдельную session для subagent, а lifecycle=true выполняет runner lifecycle setup для указанного scenario_id. persona_session_list(task_id=...) возвращает compact summaries active/suspended/completed sessions, последний snapshot и точный continuation с persona_session_state либо persona_session_resume.
  • persona_session_state возвращает сохранённый latest_observation и свежее состояние session: URL, title, load state, page errors, active element, visible summary, bounded ARIA structure summary, loaded skills/resources, lifecycle state, history summaries, draft, artifact summaries, current-state diagnostics и project fingerprint. history_tail для generation-команд содержит bounded result_summary с draft_identifiers, generated_elements, generated_collections, refactor_targets previews and counts, чтобы агент мог продолжить semantic refactor в той же session без повторной генерации. browser.aria_snapshot_summary.name_field_meaning="ARIA accessible name" отделяет поле name ARIA/YAML snapshot от PageObject-контракта, где public Page/Element name отсутствует; full_snapshot_operation подсказывает штатный typed persona_get payload для расширенного snapshot.
  • Persona MCP session владеет одним current browser state. Публичный ref имеет короткий вид eN и используется через persona_browser(session_id=..., action=..., ref=...); snapshot_id и occurrence не входят в публичный browser action. find ищет по тексту, properties, semantic path и необязательной role, а inspect читает точный узел и окружение из сохранённого semantic index без нового browser capture. persona_session_resume восстанавливает checkpoint; если live state требует повторного наблюдения, Persona снимает current snapshot и выдаёт его eN refs. Generated Page/Element, Ant/UiKit Select, Table и Repeated разрешаются по стабильному semantic/structural контракту без ref.
  • persona_make, persona_get, persona_check принимают typed operation payload из persona_knowledge, persona_project, generation manifest или support plan и пишут каждый вызов в history. После любой команды, включая произвольные вложенные Web Ops, Step и CombinedStep, ответ содержит revisioned observation: bounded result_summary, ordered operations_preview, artifact refs и при наличии browser page единый browser.current с URL/title/load state, snapshot path/revision и actionable refs; browser.changed_area содержит текущую область после navigation/tab change либо bounded diff после локального изменения. Отдельный persona_browser(action="snapshot") не требуется после каждой команды; полный ref index доступен по пути сохранённого snapshot. Tool schema содержит копируемые persona_value examples; например, текущий Python datetime передаётся как {"persona_value":"datetime","preset":"now"}, а точный — как {"persona_value":"datetime","iso":"2026-07-17T00:00:00"}. persona_value является строковым discriminator, остальные поля находятся рядом с ним. Project entity и ошибочная operation возвращают accepted_encodings, ожидаемый Python type и точный input_path; postponed annotations разрешаются до materialization. Одна authoring-команда сохраняет единую import identity project Step, generated XSD dataclass, Enum и SchemaBuilder от создания operation до завершения Step, поэтому live MCP и native runner используют один schema contract. Operation args/kwargs могут ссылаться на PageObject или вложенный element через {"persona_ref":"page","entity_id":"page::..."} и {"persona_ref":"page_element","entity_id":"page::...","path":"form.submit"}; runtime импортирует страницу внутри, агент не пишет from support.pages.... Поле code остаётся debug/escape hatch для безопасных Persona/Python expressions, которые ещё не представлены typed operation route. EN: every authoring command returns the current browser projection and bounded changed area independently of the nested operation type.
  • persona_generate_support пишет page, element, api, xsd, json и wsdl support artifacts в проект, обновляет import caches/discovery и возвращает bounded manifest с written_paths, preview/count/omitted полями для generated_pages, generated_elements, generated_collections, draft_identifiers, generated_api_operations, generated_models, generated_builders, project_entities, а также final-file imports, artifact summaries и diagnostics; file content читается из записанных project files. generated_elements содержит page_element_ref, description_source, description_refactor_required, identifier_quality и owner_boundary_evidence, чтобы semantic refactor и immediate reuse выполнялись по MCP data без чтения generated source. draft_identifiers перечисляет generated generic/value-derived/numeric/transliterated Python fields с access_path, example_ref, path/support classification и review suggestions. generated_collections описывает reusable repeated/list/grid regions через access_path, example_ref, example_item_ref, page_element_ref, prototype_type, field_count и field refs вроде page.products[0].price.
  • Успешная generation с diagnostic severity=info, например page_component_reused, возвращает status=ok; partial означает записанные артефакты с warning/error diagnostics, skipped artifacts или failed sub-operations. EN: successful generation with informational diagnostics is not a partial failure.
  • Command diagnostics относятся к текущему tool call. persona_session_state.diagnostics показывает active lifecycle/refresh/latest failed-command diagnostics and does not repeat passed generation diagnostics.
  • persona_test_author редактирует draft поверх history: state, include, remove, reorder, edit, render, write_file, reset; для semantic support refactor дополнительно принимает plan_support_file с выбранными history_ids, support_kind и target_path, возвращает advisory support_plan с ролями history, candidates, target classification, source_operations, final_file_imports, reuse_operation и live_reuse, затем write_support_file с support_kind, canonical support/{actions,steps,combined_steps,goals,facts,expectations}/**/*.py target_path и full module code, затем возвращает written_paths, final-file imports, project_entities и operations. Для check history setup statements остаются setup-кодом, а только финальное expression рендерится как persona.check(...). EN: for check history, setup statements stay as setup code and only the final expression is rendered as persona.check(...).
  • persona_test_run всегда создаёт durable launch и сохраняет UUID run_id до запуска процесса. Начальный action="run" ждёт результат в пределах test_run_inline_wait_ms: быстрый тест возвращает terminal status, item counts и report_refs тем же MCP-вызовом; продолжающийся тест возвращает status="running", run_id, launch_id и точный continuation для action="wait". action="status" читает сохранённое состояние без ожидания, action="wait" продолжает bounded ожидание, action="cancel" записывает cancel request. После running агент продолжает тот же run_id и не запускает тест повторно.
  • persona_session_close(status=passed|failed|partial) сохраняет browser checkpoint, history, receipts, snapshots и suspension record, переводит task-owned session в suspended и оставляет её доступной для persona_session_resume с тем же ID. persona_session_finalize(session_id=...|task_id=..., status=...) вызывается только при завершении task, выполняет lifecycle close/failure hooks, освобождает runtime resources и сохраняет durable evidence в registry. EN: close suspends a durable session; finalize completes one session or every session owned by the task.
  • persona_make, persona_get, persona_check и persona_browser поддерживают необязательные command_id и idempotency_key. Append-only task/session journal фиксирует started/committed events, request digest, history, receipt и artifact hashes; повтор committed payload возвращает прежний результат без повторного действия, а конфликт или незавершённая запись завершается PERSONA_SESSION_RECOVERY_FAILED. Browser resume загружает storage state в новый Playwright context, открывает реальный URL и снимает свежий semantic snapshot; сохранённый HTML не исполняется и не подставляется в страницу. EN: durable command identities provide at-most-once retry, while browser recovery restores native context state without DOM replay.

Generated API operations support request-level API profile binding: GetHealth().with_api_profile("bgt").as_response() uses skills.api.bgt, while raw JsonExchange(..., api_profile="bgt") uses the same profile selector. persona.skill("api.bgt") is accepted as shorthand for persona.skill("api", "bgt").

Element generation принимает source.kind=current_ref|current_page|fragment|snapshot и explicit placement: action add|replace|refine|extract, scope page|section|dialog|table|component, owner_path, field_name и при replace/refine existing_field_name. Package-owned knowledge surface для генераторов проверяется командами:

make knowledge-generate
make knowledge-check

Миграция Page DSL name / Page DSL name migration

RU: persona migrate page-names сканирует Page DSL-файлы проекта и формирует перенос literal name=... в description, accessible_name, text или locator по явным правилам. Команда по умолчанию работает в dry-run режиме; запись изменений включается через --apply. --path, --snapshot-root и --report задают область сканирования, RichAriaSnapshot confidence gate и путь отчёта. Мигратор распознаёт direct Page DSL classes and local component subclasses, declared in the same page file. Неперенесённые случаи остаются в исходном файле и попадают в report warnings с координатами. Для Text/Paragraph с уже заданным variants literal name=... переносится только в description, чтобы не создавать конфликт text и variants.

EN: persona migrate page-names scans project Page DSL files and prepares a literal name=... migration to description, accessible_name, text, or locator through explicit rules. The command defaults to dry-run mode; --apply enables writes. --path, --snapshot-root and --report configure the scan scope, RichAriaSnapshot confidence gate and report path. The migrator recognizes direct Page DSL classes and local component subclasses declared in the same page file. Unmigrated cases stay in source files and are listed in report warnings with coordinates. For Text/Paragraph elements that already declare variants, literal name=... migrates only to description so the migration does not create a text/variants conflict.

persona migrate page-names --project-root . --report reports/page-name-migration-report.txt
persona migrate page-names --project-root . --snapshot-root artifacts/snapshots --apply

RU: starter .venv/bin/persona migrate page-names --project-root . является thin wrapper над этой Persona CLI командой. EN: starter .venv/bin/persona migrate page-names --project-root . is a thin wrapper over this Persona CLI command.

Миграция snapshot refs / Snapshot ref migration

RU: persona migrate page-refs сканирует production Page DSL и удаляет snapshot-scoped aria_ref, header_ref и Strategy.REF. Элементы со стабильной semantic/structural strategy переписываются напрямую. Ref-only элемент материализуется из scoped project-owned snapshots: объявленный static_aria_snapshot_path имеет приоритет, затем проверяются локальные support/pages/aria/<page>_*.yaml, а project-wide snapshots используются как последняя область для вынесенного holder-файла. Persona проверяет SHA-256, выбирает element subtree либо полный table subtree для header_ref, последовательно запускает штатный generator/merge и атомарно пишет ref-free Page и связанные Python component updates. Входные snapshots остаются неизменяемым evidence: миграция не сериализует выбранный subtree в новый YAML и не меняет объявленный static_aria_snapshot_path. Одинаковая semantic identity в нескольких состояниях дедуплицируется; разные identities одного legacy ref дают диагностируемую snapshot_identity_ambiguous только внутри выбранной Page-области. Совпавший snapshot-scoped ref другой страницы не конкурирует с объявленным snapshot. Объявленные и локальные snapshots страницы валидируются всегда; project-wide fallback читается только для оставшихся legacy refs, а нерелевантный повреждённый snapshot другой страницы не блокирует миграцию.

Команда не требует Persona MCP session, task ID или session ID. При отсутствии generated state snapshots apply сохраняет все доказанно безопасные rewrite, materialization и удаления no_known_usages, а unresolved used/unknown поля оставляет с точными coordinates, usages и typed remediation action. После сохранения недостающего состояния Page повторяется та же команда. Generated и мигрированные Generic, Ant/UiKit, Table и Repeated элементы используют stable semantics и specialized structural resolvers; runtime ref в готовый Page или тест не переносится. Для безымянных Ant Select мигратор восстанавливает локальный index внутри доказанного owner-контейнера и сохраняет объявленные enum/options. Generator result без доказуемой semantic/structural strategy не считается materialization и не заменяет используемое Page field. Project reference graph строится один раз на invocation, различает прямое использование, by_variant(...) и composition holder через дочерний путь. Ref поля, которое во всех usages выбирается через by_variant(...), удаляется только когда вариант сам задаёт полную semantic identity; прямой resolve того же Text(variants=...) остаётся unresolved. Один apply удаляет все доказанно неиспользуемые поля, включая поля вложенных generated-классов, и записывает проект одной атомарной транзакцией. Удаление другого unused-поля не стирает reason, snapshot paths и usage evidence оставшегося unresolved элемента. Одинаковые имена вложенных классов различаются по exact legacy ref; при реальной неоднозначности ошибка перечисляет файл, source coordinates и все candidate assignments. CLI по умолчанию немедленно печатает line-oriented progress в stderr: discovery Page-файлов, текущий Page N/total, чтение snapshot, parse/usages каждого Python-файла при построении reference index, атомарную запись и финальные счётчики. Jenkins и перенаправленный shell log показывают активную фазу без смешивания с итоговым Markdown в stdout. --progress never отключает только progress и сохраняет отчёт и exit code. Каждый project snapshot проверяется и парсится один раз на invocation, затем его typed artifact переиспользуется для остальных Page. Согласованные отступы 2 или 4 пробела в persisted Rich ARIA snapshots сохраняют одну и ту же иерархию; конфликтующий отступ прямых потомков остаётся ошибкой структуры. Беззначные boolean properties checked, disabled, expanded, hidden, pressed и selected записываются как - /<property>; остальные properties требуют форму - /<property>: "<value>". Итоговый Markdown группирует снятые refs, восстановленные элементы, удалённые unused-поля и unresolved-действия по project-relative файлам. Восстановленное поле ссылается на конкретный snapshot evidence path; абсолютные пути и дублирующие технические action-строки в отчёт не выводятся.

EN: persona migrate page-refs replaces production snapshot refs using a Page-scoped priority: declared static_aria_snapshot_path, local Page state snapshots, then project-wide fallback for a separate holder module. It verifies every artifact, resolves refs across separate Page/Elements modules, and regenerates exact element or table subtrees through the normal structural merge without an MCP session. A ref reused by another Page cannot make the declared snapshot ambiguous. Input snapshots remain immutable evidence: migration never persists the selected subtree as a new YAML artifact or replaces the Page's declared static_aria_snapshot_path. Declared and local Page snapshots are always validated; project-wide fallback is loaded only for unresolved legacy refs, so an unrelated malformed snapshot from another Page cannot block the migration. Unnamed Ant Select controls receive an owner-local index when the verified snapshot proves their container, while authored enum/options remain intact. An unresolved generator result is retained as a typed remediation action and never replaces a used Page field. The project reference graph is built once per invocation and distinguishes direct, by_variant(...), and composition-path usage. Variant-bound fields are rewritten only when the selected variant supplies a complete semantic identity; direct resolution remains unresolved. A single apply removes every proven-unused field, including fields in nested generated classes, and writes the project through one atomic transaction. Existing reason, snapshot paths, and usage evidence survive coordinate-changing removals. Exact legacy refs disambiguate repeated nested class names; genuine ambiguity reports the file, source coordinates, and every candidate assignment. The CLI streams Page, snapshot, per-file reference-index, atomic-write and summary progress to stderr by default, including in CI and redirected logs. The final Markdown report remains isolated in stdout; --progress never disables only progress output. Each project snapshot is parsed once per invocation and its typed artifact is reused across Page files. Persisted Rich ARIA snapshots may use a consistent two- or four-space child indentation; conflicting direct-child indentation remains a structural error. Bare checked, disabled, expanded, hidden, pressed, and selected properties represent true; every other property requires - /<property>: "<value>". The report groups rewrites, materializations, unused removals, and unresolved actions under project-relative paths. Every materialized field links to its snapshot evidence path; absolute paths and duplicate raw action lines are not emitted.

persona migrate page-refs --project-root .
persona migrate page-refs --project-root . --apply
persona migrate page-refs --project-root . --apply --progress never
make migrate-page-refs APPLY=1
make migrate-page-refs

Пользовательский проект

Официальный starter расположен в template/.

  • pyproject.toml
  • config/<env>.yaml
  • config/auth.yaml
  • scenarios/**/test_*.py
  • scenarios/**/__suite__.py
  • scenario_data/
  • support/

Сценарий или ветка suite может быть отключена через disabled(reason) на test_* или suite(disabled=True, disabled_reason=...) в __suite__.py. Такие сценарии остаются в discovery/catalog с причиной, но не попадают в обычный persona run / make test; контролируемый запуск требует --include-disabled.

Команды starter:

cd template
make install
make checks
make redis
make redis action=status

Создание и обновление Persona-проекта

RU: persona project init создаёт пустой Persona-проект из template, упакованного внутрь установленного persona-dsl wheel/sdist. Команда по умолчанию работает в текущей директории; --project-root <path> указывает другой каталог. Пакетный template содержит только production skeleton: Makefile, pyproject.toml, .gitignore, persona.check.yaml, минимальный config/, пустые scenarios/ и support/, а также managed Make targets в .persona/make/persona.mk. Starter tests, starter data, учебные сценарии, reports, caches, .venv и egg-info не входят в project bootstrap.

persona project init владеет только package-owned scaffold и lifecycle state; команда не создаёт .venv. Package-owned runtime phase для интеграционных клиентов запускается managed Python без Make и без standalone-скрипта:

<MANAGED_PYTHON> -m persona_dsl.cli project install-runtime \
  --project-root <PROJECT_ROOT> --json

Эквивалентная команда установленного managed executable: persona project install-runtime --project-root <PROJECT_ROOT> --json. Она создаёт project .venv, устанавливает build/runtime/dev requirements проекта без преждевременного разрешения Persona requirement и закрепляет package-owned безопасный минимум pip для локального dependency audit, последней закрепляет distribution и точную версию Persona, которой принадлежит managed runtime, устанавливает editable project metadata с --no-deps, затем проверяет project Python, Persona CLI, MCP и LSP. Имя distribution и версия не принимаются от consumer, поэтому public и corporate builds используют identity фактически запущенного package.

Install source также принадлежит producer. Retained local source или wheel из direct_url.json преобразуется в проверенный PEP 508 direct reference и входит в content fingerprint; путь не публикуется в machine payload. При отсутствии доступного local artifact используется exact distribution==version через настроенный pip registry. Изменение retained source меняет fingerprint и запускает повторную установку той же development version.

В machine mode stderr содержит последовательные JSONL-события persona.project-runtime-install-progress, а stdout содержит один итоговый payload persona.project-runtime-install. Progress использует закрытые phase preflight, environment, dependencies, distribution, metadata, verification. Успех возвращает installed или noop и exit code 0; ошибка возвращает error, bounded diagnostic и exit code 1; ошибка синтаксиса CLI использует exit code 2. Receipt содержит exact distribution/version, проверенные executables, dependency fingerprint и путь к durable local state. Повторный вызов из проверенного project runtime возвращает исходный receipt со статусом noop без install phases. Вызов из managed runtime продолжает сравнивать provider source fingerprint и выполняет установку при его изменении.

После runtime phase Qompanion получает preview от project .venv, сохраняет plan_digest и применяет только этот plan:

<PROJECT_ROOT>/.venv/bin/persona project reconcile \
  --project-root <PROJECT_ROOT> \
  --persona-package-name <RECEIPT_DISTRIBUTION> \
  --persona-version-spec ==<RECEIPT_VERSION> \
  --dependency-mode add --json
<PROJECT_ROOT>/.venv/bin/persona project reconcile \
  --project-root <PROJECT_ROOT> \
  --persona-package-name <RECEIPT_DISTRIBUTION> \
  --persona-version-spec ==<RECEIPT_VERSION> \
  --dependency-mode add --approved-plan-digest <PLAN_DIGEST> --yes --json

stale_plan требует нового preview; consumer не применяет изменившийся plan по старому digest. Direct CLI lifecycle остаётся доступен через make install и standalone install-persona.py, но они не являются runtime API Qompanion.

RU: persona project update обновляет только Persona-owned scaffolding существующего проекта с pyproject.toml. Для пустой директории используется persona project init; update не создаёт проект и не добавляет отсутствующие README, config, scenarios/, support/, persona.check.yaml или .gitattributes. Update синхронизирует Persona sections в существующем pyproject.toml, восстанавливает отсутствующий .gitignore, синхронизирует один Persona-managed блок в существующем .gitignore и поддерживает managed Make infrastructure .persona/make/persona.mk с include в корневом Makefile. Пользовательские правила до и после bounded-блока .gitignore сохраняются; повреждённые или повторённые Persona-границы пересобираются в один канонический блок. Обычный вызов сразу применяет весь детерминированный plan без вопросов и одинаково работает в TTY и non-TTY. Результат проверяется через Git diff и историю проекта. --check, --dry-run и --diff-only являются явными read-only режимами; --interactive включает необязательный поэлементный просмотр. Для зарегистрированного packaged Makefile lifecycle синхронизирует актуальные targets в .persona/make/persona.mk и оставляет в root Makefile один include. Изменённый Makefile с Persona targets сохраняет project-owned команды и получает canonical include. Полный контент package-owned persona.mk доступен через --diff-only. Update сохраняет [project].name, [project].version, пользовательские Make targets, бизнес-тесты и данные. Corporate package задаётся явно через --persona-package-name и --persona-version-spec; Persona dependency не угадывается и не переписывается молча. persona project update предоставляет отдельный diff-first CLI, а make update-project является переходным алиасом полного make install.

Настройка agent-клиентов

make install является единым lifecycle Persona-проекта. Команда создаёт .venv, устанавливает зависимости, применяет content-addressed project plan, материализует package-owned agent surface, настраивает локальные интеграции и завершает работу через persona agent doctor. make init и make update-project являются алиасами того же пути. Установка package и согласование изменившейся project surface завершаются в одном вызове без последующей отдельной команды. Зарегистрированный старый Make lifecycle с project audit передаёт управление установленной Persona и завершает reconcile, init и doctor внутри того же make install, в том числе для Windows-проектов с CRLF. Persona-reserved MCP definitions Atlassian и Zephyr синхронизируются как secret-free project definitions; unrelated project MCP servers сохраняются.

Project-local surface содержит полный version-matched набор Persona:

  • .qwen или .gigacode с context, slash-командами, primary roles и subagents;
  • package-owned skills и workflow templates;
  • Persona-owned fragments client settings и lifecycle hooks;
  • .lsp.json с portable Persona LSP;
  • Persona MCP с точным project/worktree root для каждой сессии;
  • package-owned .persona/workflows/README.md с установкой, маршрутами и правилами продолжения задач;
  • .persona/project_memory и task packets в .persona/workflows/<task_id>/ как durable state проекта.

Reconcile вычисляет владение из package contract и текущих файлов, без project-local ownership manifest. Package-owned файлы синхронизируются с установленной Persona, bounded Persona sections в .gitignore, client context, settings, hooks и LSP объединяются структурно, а durable memory/workflow state не перезаписывается. LF и CRLF являются одной Git-проекцией package-owned UTF-8 текста; запись выполняется в canonical LF. Устаревший .persona/project/ownership.json удаляется без чтения его содержимого. Повторный make install для актуального проекта завершается без повторной материализации и без registry-операций.

Выбор встроенного agent profile задаётся при сборке Persona. Дефолт объявлен в pyproject.toml:

[tool.persona.agent_distribution]
default = "gigacode"

CI/release сборка может выпустить другой distribution без изменения template-проекта:

PERSONA_AGENT_DISTRIBUTION=qwen make build
PERSONA_AGENT_DISTRIBUTION=qwen make package-smoke
default_profile = "gigacode"
enabled_profiles = ["gigacode"]

[[profiles]]
id = "gigacode"
adapter = "gigacode"
display_name = "GigaCode Persona Agent"
scope = "project"
mcp_servers = ["persona"]
workflows = [
    "project-profile",
    "project-map",
    "test-plan",
    "test-sufficiency",
    "author-test",
    "test-run",
    "test-integration",
    "acceptance",
    "run-analysis",
    "memory-refresh",
    "quality-refactor",
]
client_command = "gigacode"

Starter user flow:

make install
make agent

make install выполняет interactive setup для локального checkout, сохраняет typed integration settings вне Git и рендерит surface выбранного клиента. Каждый запуск агента проверяет current lifecycle, binding, client runtime, project-local surface, Persona MCP и LSP. После обновления Persona повторный make install применяет только изменившийся package-owned контракт. Тот же lifecycle создаёт или обновляет .persona/workflows/README.md; README содержит standalone bootstrap для пустого каталога, make install для существующего Persona-проекта и текущий каталог slash-маршрутов.

make agent launches the selected client with the current project .venv first in PATH and with VIRTUAL_ENV set. The agent can call persona, python and rendered skill scripts without activating the environment or probing executables. make agent-continue, make agent-resume and every stage shortcut use the same runtime contract. Slash commands provide the exact initial Persona CLI invocation with the user's natural-language scope. Each successful response returns task_id, packet/state paths and one named next action; continuation uses the printed high-level route without shell JSON.

Parallel tasks use isolated Git worktrees and isolated Python environments:

make agent worktree=test-login
make agent-worktree-list
make agent worktree=test-login
make agent worktree=api-refactor worktree_root=../task-worktrees
make agent-worktree-close worktree=test-login
make agent-worktree-close worktree=test-login force=true
make agent-worktree-close worktree=test-login delete_branch=true

The first command creates branch persona/test-login from the current HEAD, then materializes the base checkout staged, unstaged and non-ignored untracked files before dependency installation. Git staging is preserved. The snapshot base, digest and paths are stored under ignored .persona/local; a reused worktree rejects a different dirty source snapshot instead of overwriting task work. Each worktree owns its .venv, and make install runs when its dependency fingerprint changes. The worktree .venv/bin/persona renders its own project-local surface and proves the high-level route contract before the model client starts. Project-local settings and runtime files are synchronized separately: .persona/local/agent-bootstrap.local.json, config/auth.yaml, .env, .env.* and config/auth.*.yaml; *.example* files are excluded. make agent-worktree-list prints registered Persona worktrees with path, branch and clean status. make agent-worktree-close worktree=<name> runs git worktree remove for a clean Persona-owned worktree and then git worktree prune. Dirty worktrees stop with a warning; force=true removes the working directory through git worktree remove --force. delete_branch=true also removes the local persona/<name> branch; with force=true it uses git branch -D.

Client runtime lifecycle is distribution-owned. A required Qwen profile writes private settings to .persona/local/client-runtime/<profile-id>/settings.json and passes the file through QWEN_CODE_SYSTEM_SETTINGS_PATH; Persona does not rewrite user or project Qwen settings. Qwen SessionStart, PreCompact, Stop, StopFailure, SessionEnd and scoped tool-failure hooks bind the exact client session and attach the current task, flow, route, packet, finding, knowledge lookup and continuation. Hook diagnostics are context and do not block model, tool, command or delegation execution. persona agent client-status renders the read-only task/stage/gap/context status line. Managed Qwen automatic, team and dream memory are disabled because Persona project memory owns durable project knowledge.

The tracked .qwenignore excludes local runtime/cache/view paths from Qwen file discovery without hiding durable workflow packets, reviewed memory or project sources. persona agent doctor --project-root . validates lifecycle state, client version, binding, project-local inventory, settings ownership, MCP, LSP and context policy.

Direct CLI flow:

persona agent init --project-root .
persona agent launch --project-root . --mode new
persona agent launch --project-root . --mode continue
persona agent launch --project-root . --mode resume --session-id <session-id>

make agent delegates to the same typed launcher and starts the selected client without choosing a workflow. A raw qwen or gigacode command remains an ordinary non-Persona session. The user selects a concrete route with /persona.<route> inside the Persona session. Long-running role entrypoints keep separate commands because they select a package-owned primary prompt rather than a route.

Long-running test work can start with a primary role without choosing a route, task or packet:

make agent-test-analysis
make agent-test-author

agent-test-analysis starts the current client as the test-analysis owner and waits for /persona.test-sufficiency .... agent-test-author starts it as the test-authoring owner and waits for /persona.author-test .... The slash command binds the concrete route and task inside the open session; the current agent executes that route directly. Files under agents/persona-*.md define bounded child-agent assignments.

Qwen и GigaCode получают одинаковый capability catalog: route-команды, четыре bundled skill, route reference, system prompt, workflow packet templates, primary roles и subagent assignments. Renderer размещает эти файлы в namespace конкретного проекта и сверяет Persona-reserved paths с package contract. Project path, credentials и runtime settings не встраиваются в package-owned тексты.

persona agent init проверяет current project lifecycle, настраивает private client runtime и binding, проверяет MCP/LSP и выполняет resumable migration старых project-specific registry entries. persona agent legacy-scan доступен только для аудита legacy installations. Registry entry удаляется после успешной проверки project-local surface и launch; старый generated source удаляется при полном совпадении ownership hashes. Доказанный managed source с client-generated cache сохраняется в content-addressed private recovery .persona/local/recovery/legacy-agent-extensions/ и удаляется из .persona/agent_extensions; изменённый или не подтверждённый source остаётся на месте с явным conflict.

Typed launcher читает system prompt из .<client>/persona, проверяет обычные project MCP definitions и запускает vendor CLI без shell, extension flags и временного MCP config. Slash-команда выбирает workflow внутри открытой сессии. Route использует durable Markdown packet, project-memory receipts и обязательные views; stdout агента не является workflow evidence. Локальные интеграции настраиваются во время интерактивного make install или точными recovery-командами persona agent init --project-root . --configure-atlassian, --configure-css и --configure-zephyr. Значения Atlassian, CSS и Zephyr хранятся в git-ignored .persona/local/agent-bootstrap.local.json; process environment проецируется в git-ignored .env с сохранением пользовательских переменных.

Atlassian runtime находится в .persona/local/atlassian-mcp/.venv, содержит закреплённые версии mcp-atlassian, redis и Authlib и запускается с READ_ONLY_MODE=false и TOOLSETS=all. Zephyr использует persona-zephyr-mcp из project .venv, project-local журнал .persona/mcp/zephyr-mcp.log и trust=false. Credentials не попадают в tracked client settings, workflow packets или MCP definition.

make install добавляет Persona и настроенные Atlassian/Zephyr integrations в обычный project-local .qwen/settings.json или .gigacode/settings.json. Definitions содержат переносимые команды, cwd, timeout и trust без credentials. Приватные значения хранятся в .persona/local/agent-bootstrap.local.json, проецируются в .env и передаются дочернему client process через environment. make agent проверяет executable каждого настроенного сервера и передаёт клиенту точный список разрешённых имён отдельными значениями --allowed-mcp-server-names. Persona MCP получает фактический project/worktree root. Обычный vendor CLI, запущенный в проекте, использует ту же project MCP поверхность без global extension.

Для transport-диагностики .venv/bin/persona-zephyr-mcp --project-root . запускает long-lived server в foreground. Журнал содержит JSON-RPC request start/end, safe issue/test keys, status, diagnostic и elapsed time; PAT, Authorization и protocol bodies не записываются. zephyr_test_case_get читает до 50 шагов на страницу, а большие значения продолжает через точный JSON Pointer в zephyr_test_case_value.

Tracked project state включает Persona-managed client surface, .persona/make/persona.mk, .persona/project_memory/memory.jsonl, .persona/project_memory/sources/** и .persona/workflows/**. Binding, local settings, runtime projections, context packs, rendered views, retrieval indexes, MCP logs, dependencies, databases, locks и временные файлы игнорируются Git. .gitattributes назначает merge=union для memory JSONL; derived views пересобираются через make memory action=render.

artifact-hygiene использует тот же закрытый path contract: managed Make, memory JSONL, source provenance и workflow packets разрешены; runtime, backups и неизвестные пути внутри .persona считаются локальными артефактами и не должны попадать в Git.

Повторный make install сверяет dependency fingerprint, report runtime, content-addressed project plan, client binding, MCP/LSP и doctor. Совпадающий контракт возвращает noop; устаревший package-owned artifact обновляется одной project transaction. Локальные secrets при reconcile не переписываются.

Сценарии Persona Agent

task_id идентифицирует один flow, объявленный в Identity.flow. Route видит packets и receipts этого flow. Project-discovery передаёт другим flows принятую project memory, но не свои packets.

Flow Тип Entry Completion Routes
project-discovery composed project-profile, project-map project-profile, project-map project-profile, project-map
memory-maintenance atomic memory-refresh memory-refresh memory-refresh
new-test composed test-plan test-integration, acceptance test-plan, test-sufficiency, author-test, test-run, run-analysis, test-integration, acceptance
manual-case-automation composed test-sufficiency, author-test test-integration, acceptance test-sufficiency, author-test, test-run, run-analysis, test-integration, acceptance
test-execution composed test-run, run-analysis, acceptance test-run, test-integration, acceptance test-run, run-analysis, author-test, test-integration, acceptance
quality-campaign atomic quality-refactor quality-refactor quality-refactor

Условия входа

  • project-discoveryproject-profile: Маршруты задач, требований, ручных кейсов или automation неизвестны либо устарели.
  • project-discoveryproject-map: Источники уже названы в запросе либо существует accepted project profile.
  • memory-maintenancememory-refresh: Названы изменившиеся источники принятой project memory.
  • new-testtest-plan: Нужно спроектировать новый ручной кейс до live-проверки.
  • manual-case-automationtest-sufficiency: Существует исходный ручной кейс, который нужно проверить перед автоматизацией.
  • manual-case-automationauthor-test: Пользователь прямо просит написать тест и принимает доступные исходные данные как authoring input; отсутствующие существенные факты уточняются внутри author-test.
  • test-executiontest-run: Нужно запустить известный существующий сценарий.
  • test-executionrun-analysis: Уже известен конкретный failed или ambiguous run.
  • test-executionacceptance: Есть полный свежий evidence существующего теста и требуется только acceptance decision.
  • quality-campaignquality-refactor: Задан project или test scope strict quality campaign.

Индекс: persona_knowledge(action="agent_flows"). Полный flow: persona_knowledge(action="agent_flow", flow_id="<flow>"). Точный route: persona_knowledge(action="agent_route", route="<route>").

Bundled skills are domain playbooks, not extra slash-command stages:

  • persona-project-memory is used by project-map, memory-refresh and source-backed test planning. It owns scoped source evidence, Confluence parent/child checklists, reviewed memory records, gaps, context packs and view refresh decisions.
  • persona-test-authoring is used by live test-sufficiency, author-test and code-changing test-integration. In sufficiency mode it owns runtime traversal evidence without code writes; authoring mode owns support generation, Page/Step/Fact/Expectation structure, persona_test_author draft/write and runner verification.
  • persona-run-evidence is used by test-run, run-analysis and acceptance. It owns UUID run_id, session/run binding, report refs, failure taxonomy, acceptance packets and post-run memory updates.
  • persona-quality-refactor is used by quality-refactor. It owns the strict baseline, structure/guides/suppression reviews, dependency-ordered root-cause plan, bounded remediation checkpoints, repeated gates and final evidence.

Slash commands remain the user workflow; skills are the reusable professional behavior the launched agent applies inside that workflow.

Atlassian-scoped project-map examples:

/persona.project-map agent_args="source=confluence:SPACE-123 include_children=true"
/persona.project-map agent_args="source=confluence:987654 include_children=false"
/persona.test-plan jira=PROJ-123

Inside GigaCode the same parameters are passed directly to slash workflows:

/persona.project-map task_id=auth-map source=confluence:SPACE-123 include_children=true
/persona.project-map task_id=repo-map source=repo:pyproject.toml
/persona.test-plan jira=PROJ-123 source=confluence:987654
/persona.project-map составь карту по Confluence page 987654 с дочерними страницами
/persona.test-plan подготовь план по Jira PROJ-123 и Confluence 987654

include_children=true means the agent must build a Source Checklist for the parent Confluence page and each discovered child before extraction. Missing Atlassian access or unreadable child pages become project-memory gap records. Natural-language slash input is accepted when it contains a concrete Jira key, Confluence page id or scope ref; the agent canonicalizes it to the same scoped arguments and must ask for the missing identifier instead of broad searching.

Cognee-backed project memory is an optional package extra and project config:

pip install "persona-dsl[memory-cognee]"
[tool.persona.project_memory]
provider = "cognee"
dataset_name = "persona_project"
top_k = 15
use_domain_graph_model = true
self_improvement = false
include_backend_context = true

Persona keeps one MCP server. GigaCode/Qwen calls persona_project_memory; Persona ingests raw sources into Cognee as the project-local graph/vector backend and keeps reviewed records in .persona/project_memory/memory.jsonl.

persona memory status --project-root .
persona memory view --project-root .
persona memory serve --project-root . --host 127.0.0.1 --port 8776

Runtime Event Sink

Persona публикует runtime-события во внешний sink через нейтральный contract:

  • PERSONA_EVENT_SINK=redis_stream
  • PERSONA_EVENT_REDIS_URL=redis://localhost:6379/0
  • PERSONA_EVENT_STREAM_KEY=persona:{launch_id}:events
  • PERSONA_EVENT_STREAM_MAXLEN=10000
  • PERSONA_EVENT_STRICT_CONNECT=false

При отключённом sink локальные runtime/report artifacts продолжают писаться в проектные директории. Starter поднимает локальный Redis через template/compose.yaml:

cd template
make redis
make redis action=status

Data Pools

runtime.data_pools описывает эксклюзивные элементы для параллельных запусков. Типизированный resource объявляется обычным классом в support/resources:

from persona_dsl import Persona, leased_resource


@leased_resource("parallel.user", pool="parallel_users")
class ParallelUser:
    item_id: str
    username: str
    password: str


def test_parallel_login(persona: Persona) -> None:
    user = persona.resource(ParallelUser)
    login(user.username, user.password)

@leased_resource сам создаёт strict frozen/slotted dataclass. item_id берётся из lease envelope, остальные поля класса — из одноимённых ключей payload. Лишние, отсутствующие и несовместимые по типу поля завершают получение ресурса диагностируемой ошибкой. Runtime берёт lease при фактическом persona.resource(ParallelUser) и освобождает его через lifecycle test-scoped resource. define_lease_resource(...) остаётся для ресурсов с пользовательской фабрикой, преобразованием или cleanup.

config/dev.yaml связывает pool с отдельным YAML-файлом:

runtime:
  data_pools:
    parallel_users:
      backend: "local_sqlite"
      acquire_timeout_sec: 30
      lease_ttl_sec: 300
      heartbeat_interval_sec: 30
      items_source:
        path: "scenario_data/data_pools/parallel_users.yaml"
        format: "yaml"

scenario_data/data_pools/parallel_users.yaml содержит элементы пула:

- item_id: "parallel_user_01"
  payload:
    username: "test-user-01"
    password: "credential-placeholder-01"

Элемент пула требует только item_id. auth_key задаётся для ресурсов, которые читают credentials через persona.auth(...); несекретные значения хранятся в payload.

Redis backend для data pools читает URL из env-переменной, указанной в runtime.data_pools.<pool_id>.redis.url_env. Starter содержит env=redis и пример .env.redis.example:

  • PERSONA_DATA_POOL_REDIS_URL=redis://localhost:6379/0
  • PERSONA_EVENT_REDIS_URL=redis://localhost:6379/0

dev и staging используют local_sqlite; Redis-режим выбирается явно через env=redis.

Knowledge

Package-owned knowledge включает guide, framework/config catalogs, retrieval corpus и build-time completeness inventory. Проверка выполняется через:

make knowledge-generate
make knowledge-check

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

persona_dsl-2026.8.4rc184.tar.gz (11.1 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

persona_dsl-2026.8.4rc184-py3-none-any.whl (11.7 MB view details)

Uploaded Python 3

File details

Details for the file persona_dsl-2026.8.4rc184.tar.gz.

File metadata

  • Download URL: persona_dsl-2026.8.4rc184.tar.gz
  • Upload date:
  • Size: 11.1 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.13

File hashes

Hashes for persona_dsl-2026.8.4rc184.tar.gz
Algorithm Hash digest
SHA256 d539aa00b0ed3bcd735a83cf9eb33f21104ef6fa21b99003be253224e6740da4
MD5 cb177dfd7fc860bab537e93e5331ee46
BLAKE2b-256 eb83fee54cd2ebe08cbd37471f0fb8dbf52449825ed7297f35be725876ed7d8f

See more details on using hashes here.

File details

Details for the file persona_dsl-2026.8.4rc184-py3-none-any.whl.

File metadata

File hashes

Hashes for persona_dsl-2026.8.4rc184-py3-none-any.whl
Algorithm Hash digest
SHA256 e101b78744c01b426c1486815a45fa3a5c176d10bb6eb91f5aeccb26d49e4bcc
MD5 639b62ccff4e3639e8121f121abc9c85
BLAKE2b-256 80cd6fb80f65f350adf8374beb0516530b4560782bc9f8dfc3f750d23894c93c

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

2026.8.4rc184 This release

2 files

2026.7.3

2 files

2026.4.24

2 files

2026.4.21

2 files

2026.4.19.1

2 files

2026.4.8.1

2 files

2026.2.25

2 files

2026.2.9

2 files

26.2.4.61

2 files

26.2.3.59

2 files

26.1.22.53

2 files

26.1.21.47

2 files

26.1.21.45

2 files

26.1.21.44

2 files

26.1.21.43

2 files

26.1.21.42

2 files

26.1.21.41

2 files

26.1.21.39

2 files

26.1.21.38

2 files

26.1.21.37

2 files

26.1.21.34

2 files

26.1.21.32

2 files

26.1.21.30

2 files

26.1.21.28

2 files

26.1.21.26

2 files

26.1.20.16

2 files

26.1.20.14

2 files

26.1.20.12

2 files

26.1.20.11

2 files

26.1.20.10

2 files

26.1.20.9

2 files

26.1.20.8

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page