{% extends "base.html" %} {% block title %}{{ name }}{% endblock %} {# One skill, in the order somebody works through it: where its copies are and which one loads, what is wrong, and what it says. The rail holds what flanner itself has on the skill — how often it was used, which versions are kept, what the team sent. Those are reference you glance at while reading the package, not steps in reading it, and underneath the manifest they sat three screens past the thing they describe. Same split as the plan viewer, for the same reason. #} {% block topbar_back %} {% endblock %} {% block topbar_main %}

{{ name }}

{{ loaded.agent }} · {{ loaded.scope }}{% if loaded.plugin %} · {{ loaded.plugin }}{% endif %} {%- if copies | length > 1 %} · {{ copies | length }} copies{% endif %} {% endblock %} {% block content %}
{% if said %}
{{ said }}
{% endif %} {# The skill's own description, as the top of the page rather than a card of its own. It is written for the agent, not for a person: of the 109 packages on this machine 81 run past 220 characters and the median is 335, most of it "Use when ..." routing text. A card gave all of that the same weight as the manifest. Two lines, and the rest on a click. #} {% if loaded.description %} {% if loaded.description | length > 170 %}
{{ loaded.description }}
{% else %}

{{ loaded.description }}

{% endif %} {% endif %} {# --- every copy ------------------------------------------------------ #} {# "Copies of this name" only described the page when there were several. On the common case - one copy - it asked a question nobody had, when the table is just saying where the skill is and who reads it. #}
Where it lives {% if copies | length > 1 %}{{ copies | length }} copies · {{ copies | selectattr('effective') | list | length }} loads {%- else %}one copy{% endif %}
AgentScopeWhere ContentsLoads
{% for copy in copies %}
{{ copy.agent }} {{ copy.scope }}{% if copy.revision %} {{ copy.revision }}{% endif %} {{ copy.plugin or copy.scope }} {{ copy.directory }} {{ copy.manifest_hash[:23] }}… {{ copy.file_count }} files {% if copy.effective %}loads {% else %}shadowed{% endif %}
{% endfor %}
{% if copies | length > 1 %}

{% if ambiguous %} {{ ambiguous | join(' and ') }} loads more than one of these and does not resolve a name collision, so which one runs is not decided here. Give them different names, or delete the one you did not mean to keep. {% elif agents | length > 1 %} {{ agents | join(' and ') }} each load their own. A name held by two agents is two skills, not a collision — they are read from different directories by different programs. {% else %} The others are on disk and never read. Editing one of them is the usual cause of “my change did nothing”. {% endif %}

{% endif %}
{# --- what is wrong --------------------------------------------------- #} {% if findings %}
What is wrong {{ findings | length }}
FindingDetailWhat to do
{% for f in findings %}
{{ f.code }} {{ f.detail }} {%- if f.evidence %} {# The domain joins these with "; " because that is what the CLI prints. A column is not a line of terminal output, so the page takes them apart again and clips each one at the head. #} {%- for where in f.evidence.split('; ') %} {{ where }} {%- endfor %} {%- endif %} {{ f.remedy }}
{% endfor %}
{% endif %} {# --- how the copies differ ------------------------------------------- #} {% for change in differences %}
How the {{ change.against.scope }} copy differs {{ change.against.directory }}

{% if change.differing %}{{ change.differing | length }} file(s) differ: {{ change.differing | join(', ') }}.{% endif %} {% if change.only_left %}Only in the copy that loads: {{ change.only_left | join(', ') }}.{% endif %} {% if change.only_right %}Only in this one: {{ change.only_right | join(', ') }}.{% endif %} {% if not change.manifest_diff %}The manifests are the same; the difference is elsewhere in the package.{% endif %}

{% if change.manifest_diff %}
{% for line in change.manifest_diff %}{% if line.startswith('+') %}{{ line }}{% elif line.startswith('-') %}{{ line }}{% elif line.startswith('@') %}{{ line }}{% else %}{{ line }}
{% endif %}{% endfor %}
{% if change.diff_truncated %}

Cut short. Past this the answer is that these are not the same package.

{% endif %} {% endif %}
{% endfor %} {# --- what it says ---------------------------------------------------- #}
What it says {{ loaded.directory }}
{% if prose %}
{{ prose | safe }}
{% else %}

The manifest could not be read.

{% endif %}
FileSize
{% for file in files %}
{{ file.path }}{% if file.manifest %} manifest{% endif %} {{ file.size_bytes }} B
{% endfor %}

These are the files the package's hash covers. Nothing in one is executed by a scan, and flanner never writes into a directory an agent owns.

{# --- proposals ------------------------------------------------------- #} {% if proposals %}
Waiting on a decision {{ proposals | length }}
DraftActionStateWhy
{% for row in proposals %}
{{ row.draft_hash[:16] }}… {{ row.action }} {{ row.state }} {{ row.rationale }} Read it
{% endfor %}

A change to a skill arrives as a proposal and is read before it is installed. Nothing an agent suggests edits a package on its own.

{% endif %}
{% endblock %}