Skip to content

Instantly share code, notes, and snippets.

@possibilities
Created March 11, 2026 16:03
Show Gist options
  • Select an option

  • Save possibilities/b675803ced894ee827a6612e457919f4 to your computer and use it in GitHub Desktop.

Select an option

Save possibilities/b675803ced894ee827a6612e457919f4 to your computer and use it in GitHub Desktop.
geminctl render-markdown example — Gemini implementation session rendered as markdown
session-id backend model start-time
ee0f6c4c-61c8-438a-9172-42ca9efc47fe
gemini
gemini-2.5-pro
2026-02-20T02:53:11.321Z

User

Implement the following plan. Return the complete modified files - show the FULL file content for each file, not just diffs or snippets.

Strict primer validation for invoke-pipeline

Context

The primer in invoke-pipeline loads a command markdown file and appends it to the agent's system prompt. Currently load_primer_context() silently returns empty string when a primer can't be found, so the agent runs without CLI tools context and nobody notices. The primer should require the full qualified name (arthack:developer) and fail loudly before the pipeline starts if it can't resolve.

What to change

1. load_primer_context — use plugin name for targeted lookup, error on miss

File: apps/skillctl/skillctl/pipeline_loader.py:154-182

Current behavior: strips plugin prefix, searches all plugins, returns "" on miss.

New behavior:

  • Normalize: strip leading /, require format plugin_name:command_name
  • If : present: find the matching plugin by directory name from find_all_plugins(), look in that plugin's commands/ dir only
  • If no :: raise click.ClickException — bare names are no longer accepted
  • If the command file doesn't exist: raise click.ClickException with a helpful message naming the primer and the path searched

find_all_plugins() (apps/skillctl/skillctl/helpers.py:226-237) returns list[Path] where each Path.name is the plugin directory name (e.g. arthack, claude, git). Use path.name to match the plugin prefix.

_strip_command_template() (apps/skillctl/skillctl/pipeline_loader.py:235-247) is already correct — reuse it.

2. Validate primer early in run() and resolve once

File: apps/skillctl/skillctl/run_invoke_pipeline.py:125-129

Change default from "worker" to "arthack:worker":

primer = (
    getattr(args, "primer", None)
    or (pipeline_config.primer if pipeline_config else None)
    or "arthack:worker"
)

Then immediately validate by calling load_primer_context(primer). Since it now raises on failure, the pipeline won't start if the primer is bad. Store the result as primer_context.

3. Stop re-resolving primer per step — pass the content down

Currently primer (the string name) is threaded through run()_execute_pipeline()_run_skill_step_with_watchdog()_run_skill_step(), and load_primer_context() is called again inside _run_skill_step() at line 533-537.

Change the parameter from primer: str to primer_context: str through this chain:

  • _execute_pipeline() signature at line 222: primer: str | None = Noneprimer_context: str = ""
  • Both call sites at lines 319 and 336: primer=primerprimer_context=primer_context
  • _run_skill_step() signature at line 486: primer: str | None = Noneprimer_context: str = ""
  • Inside _run_skill_step() at lines 533-537: remove the load_primer_context / load_developer_context calls, just use primer_context directly:
    developer_context = primer_context
  • The load_developer_context import at line 513 can be removed

4. Update CLI help text

File: apps/skillctl/skillctl/cli.py:313

Change help from "Primer command name for system prompt (overrides YAML)" to "Primer slash command, e.g. arthack:developer (overrides YAML)".

5. Update searching-for-jobs pipeline YAMLs

All three files — change primer: developer to primer: arthack:developer:

  • /Users/mike/code/searching-for-jobs/pipelines/search-and-apply.yaml:3
  • /Users/mike/code/searching-for-jobs/pipelines/search.yaml:3
  • /Users/mike/code/searching-for-jobs/pipelines/apply.yaml:3

Not in scope

  • Changing invoke-skill (single-step runner in helpers.py) — it uses load_developer_context() directly, no primer support
  • Adding primer support to other commands
  • Changing the pipeline YAML schema validator beyond what's already there for the primer field

Gotchas

  • find_all_plugins() already includes the arthack plugin (it calls find_arthack_plugin() internally), so you don't need both
  • _run_skill_step_with_watchdog() at line 915 just passes **step_kwargs through to _run_skill_step(), so changing the kwarg name from primer to primer_context flows through automatically
  • The load_developer_context() function in helpers.py:70 is still used by invoke-skill — don't remove it, just remove its import from _run_skill_step

Verification

# 1. Qualified name resolves
uv run python3 -c "
from skillctl.pipeline_loader import load_primer_context
r = load_primer_context('arthack:developer')
assert len(r) > 10000, f'Expected >10K chars, got {len(r)}'
assert 'Core Stance' in r
print('OK: arthack:developer resolves')
"

# 2. Bare name raises error
uv run python3 -c "
import click
from skillctl.pipeline_loader import load_primer_context
try:
    load_primer_context('developer')
    print('FAIL: should have raised')
except click.ClickException as e:
    print(f'OK: bare name rejected: {e.message}')
"

# 3. Bad plugin name raises error
uv run python3 -c "
import click
from skillctl.pipeline_loader import load_primer_context
try:
    load_primer_context('nonexistent:foo')
    print('FAIL: should have raised')
except click.ClickException as e:
    print(f'OK: bad plugin rejected: {e.message}')
"

# 4. Bad command name raises error
uv run python3 -c "
import click
from skillctl.pipeline_loader import load_primer_context
try:
    load_primer_context('arthack:nonexistent')
    print('FAIL: should have raised')
except click.ClickException as e:
    print(f'OK: bad command rejected: {e.message}')
"

# 5. Default 'arthack:worker' resolves
uv run python3 -c "
from skillctl.pipeline_loader import load_primer_context
r = load_primer_context('arthack:worker')
assert len(r) > 10000
print('OK: arthack:worker resolves')
"

[File: apps/skillctl/skillctl/pipeline_loader.py]

[File: apps/skillctl/skillctl/run_invoke_pipeline.py]

[File: apps/skillctl/skillctl/cli.py]

[File: apps/skillctl/skillctl/helpers.py]

Thought (4 entries)

Assistant

I will implement the requested changes. First, I will read the necessary files to get their current content.

List (error, 1 line)

Thought (1 entries)

Assistant

I cannot access the YAML files located in /Users/mike/code/searching-for-jobs/pipelines/ as they are outside of the current project workspace. I will proceed with the modifications to the files within the apps/skillctl directory.

Read apps/skillctl/skillctl/pipeline_loader.py (248 lines)

Thought (1 entries)

Assistant

Got it. I'm moving on to the next files.

Read apps/skillctl/skillctl/run_invoke_pipeline.py (1453 lines)

Thought (1 entries)

Assistant

Okay, I've read run_invoke_pipeline.py. Now reading cli.py and helpers.py.

Read apps/skillctl/skillctl/cli.py (389 lines)

Thought (1 entries)

Assistant

Okay, I've read cli.py, now reading helpers.py.

Read apps/skillctl/skillctl/helpers.py (555 lines)

Thought (2 entries)

Assistant

Files read. Now, to modify pipeline_loader.py for the new load_primer_context logic. Then, I'll update run_invoke_pipeline.py to use it, threading primer_context down to _run_skill_step. I'll also update the --primer help text in cli.py. Finally, I'll notify the user to manually update the inaccessible YAML files. Starting with pipeline_loader.py.

Edit ~/code/arthack/apps/skillctl/skillctl/pipeline_loader.py (1 line)

Thought (2 entries)

Assistant

Okay, pipeline_loader.py is done. Now for run_invoke_pipeline.py. I'll update the default primer to arthack:worker, validate it with load_primer_context, and thread the resulting primer_context through _execute_pipeline and _run_skill_step, removing old primer logic and the load_developer_context import. One replace call will do it.

Read apps/skillctl/skillctl/run_invoke_pipeline.py (1453 lines)

Thought (1 entries)

Assistant

Okay, modifying apps/skillctl/skillctl/run_invoke_pipeline.py now.

Edit ~/code/arthack/apps/skillctl/skillctl/run_invoke_pipeline.py (1 line)

Thought (1 entries)

Assistant

Modified run_invoke_pipeline.py. Now updating help text in cli.py.

Edit ~/code/arthack/apps/skillctl/skillctl/cli.py (1 line)

Thought (2 entries)

Assistant

Okay, arthack file mods are done. I couldn't touch /Users/mike/code/searching-for-jobs/ due to workspace restrictions, which I need to report. Now, I'm running the verification steps.

Shell uv run python3 -c " from...nce' in r print('OK: arthack:developer resolves') " (2 lines)

Thought (1 entries)

Assistant

Step 1 passed. Step 2 next.

Shell uv run python3 -c " impo... print(f'OK: bare name rejected: {e.message}') " (2 lines)

Thought (1 entries)

Assistant

Step 2's done. On to step 3.

Shell uv run python3 -c " impo... print(f'OK: bad plugin rejected: {e.message}') " (2 lines)

Thought (1 entries)

Assistant

Step 3 done, on to step 4.

Shell uv run python3 -c " impo... print(f'OK: bad command rejected: {e.message}') " (2 lines)

Thought (1 entries)

Assistant

Step 4 done. Time for step 5.

Shell uv run python3 -c " from...n(r) > 10000 print('OK: arthack:worker resolves') " (2 lines)

Thought (2 entries)

Assistant

Verification passed. I've implemented the changes, excluding out-of-workspace YAMLs. I'll now send the final response with the modified files and a note about the YAMLs.

Read apps/skillctl/skillctl/pipeline_loader.py (254 lines)

Thought (1 entries)

Assistant

Read modified files, then finish.

Read apps/skillctl/skillctl/run_invoke_pipeline.py (1451 lines)

Thought (1 entries)

Assistant

Okay, rereading apps/skillctl/skillctl/cli.py for the final version.

Read apps/skillctl/skillctl/cli.py (389 lines)

Thought (1 entries)

Assistant

Okay, I've reviewed the modified files and am ready to present the final result. I'll provide the complete file content as requested, and I'll also note which YAML files were inaccessible.

Thought (1 entries)

Assistant

Files read. Ready to respond.

User

System: Please continue.

Assistant

Okay, I've reviewed the files and am ready to generate the response.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment