Claude Skill

refocusing

Use when a long-running agent may have lost the product outcome, when context was compacted, when work has crossed a major boundary, or when a fresh path-based trace is needed before the next consequential action. Not for fresh-session orientation, waking an idle seat, or checkpo

LLM Mart · 0 points · 11 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download mvschwarz-openrig-packages_daemon_assets_plugins_openrig-core_skills_refocusing-209030f.zip · 4 KB
Part of mvschwarz/openrig — 47 skills

Install

skills CLI npx skills add https://github.com/mvschwarz/openrig/tree/main/packages/daemon/assets/plugins/openrig-core/skills/refocusing
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install mvschwarz-openrig@llmmart
Git git clone https://github.com/mvschwarz/openrig.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole mvschwarz/openrig collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

Refocusing

Refocus preserves a long session's earned expertise while re-grounding it in current intent and lived context. It is not a restart, wake, or phase checkpoint.

Run the bundled trace from this skill directory instead of reconstructing the hierarchy from memory:

python3 scripts/trace-to-root.py --trees both --depth light

Use --trees topology|work|both to select context domains and --depth light|full to control how much each node contributes. Light work traces compose intent: and name notes; full traces include the complete node and notes bodies. The script resolves topology.root and workspace.root with rig config get. When a current node cannot be derived, set OPENRIG_REFOCUS_TOPOLOGY_NODE or OPENRIG_REFOCUS_WORK_NODE, or pass the matching --*-start option.

Read references/refocus.md when changing the automatic hook or its content ladder. A missing chain file is evidence: report the gap and continue; never follow pointers to invent a second parent.

Files (openrig)
  • references
    • refocus.md 1.1 KB
      # Refocus
      
      1. What is the person actually trying to get? Not your current task — the outcome.
      2. Does what you are doing RIGHT NOW move that? If you cannot say what a user gets, stop and say so.
      3. What have you concluded without opening the file or running the thing?
      
      Discomfort on any of these is the signal: drift feels like work.
      
      The `refocusing` skill carries the source-appropriate path-only trace. Its
      `scripts/trace-to-root.py` walks both current trees by default: topology `LEARNED.md`, then work
      `SPEC.md` intent plus `NOTES.md`. Change breadth with `OPENRIG_REFOCUS_TREES=topology|work|both`
      and read depth with `OPENRIG_REFOCUS_DEPTH=light|full`.
      
      Replace this default without editing the plugin. The content ladder, highest precedence first, is:
      
      1. `OPENRIG_REFOCUS_CONTENT_REF`, resolved by `rig context get`.
      2. `OPENRIG_REFOCUS_CONTENT_FILE`, an operator-authored file.
      3. `$OPENRIG_HOME/refocus/REFOCUS.md`, instance content.
      4. This shipped default.
      
      Fresh seats receive the separate onboarding assets `openrig-onboarding-01.md` and
      `openrig-onboarding-02.md`. This file only cites those assets; it does not copy their world install.
      
  • scripts
    • trace-to-root.py 9.5 KB
      #!/usr/bin/env python3
      """Render topology and work context by ascending directory paths only."""
      
      import argparse
      import json
      import os
      import re
      import subprocess
      from pathlib import Path
      
      SHELVES = {"rigs", "pods", "seats", "missions", "slices"}
      
      
      def rig_output(*args):
          try:
              result = subprocess.run(
                  ["rig", *args], capture_output=True, text=True, timeout=10, check=False
              )
          except (OSError, subprocess.SubprocessError):
              return None
          value = (result.stdout or "").strip()
          return value if result.returncode == 0 and value else None
      
      
      def configured_root(key, env_key):
          value = os.environ.get(env_key) or rig_output("config", "get", key)
          return Path(value).expanduser().resolve() if value else None
      
      
      def under_root(path, root):
          try:
              path.relative_to(root)
              return True
          except ValueError:
              return False
      
      
      def ascent(start, root):
          start = start.expanduser().resolve()
          if not under_root(start, root):
              return None, f"start is outside configured root: {start}"
          nodes = []
          current = start
          while True:
              if current.name not in SHELVES:
                  nodes.append(current)
              if current == root:
                  break
              parent = current.parent
              if parent == current:
                  return None, f"could not reach configured root: {root}"
              current = parent
          return list(reversed(nodes)), None
      
      
      def read(path):
          try:
              return path.read_text(encoding="utf8", errors="replace")
          except OSError:
              return None
      
      
      def resolve_notes(node):
          try:
              result = subprocess.run(
                  ["rig", "scope", "resolve-notes", str(node), "--json"],
                  capture_output=True,
                  text=True,
                  timeout=10,
                  check=False,
              )
          except subprocess.TimeoutExpired:
              return None, "resolver command timed out"
          except OSError as error:
              return None, f"resolver command could not start: {error}"
          if result.returncode != 0:
              detail = (result.stderr or result.stdout or "").strip().splitlines()
              suffix = f": {detail[0]}" if detail else ""
              return None, f"resolver command exited {result.returncode}{suffix}"
          try:
              payload = json.loads(result.stdout)
          except (json.JSONDecodeError, TypeError):
              return None, "resolver command returned malformed JSON"
          if not isinstance(payload, dict) or payload.get("ok") is not True or "resolution" not in payload:
              return None, "resolver command returned an invalid success shape"
          resolution = payload["resolution"]
          if resolution is None:
              return None, None
          if not isinstance(resolution, dict):
              return None, "resolver command returned an invalid resolution shape"
          resolved_path = resolution.get("path")
          resolved_name = resolution.get("name")
          if not isinstance(resolved_path, str) or not isinstance(resolved_name, str):
              return None, "resolver command returned an invalid resolution shape"
          return (Path(resolved_path), resolved_name), None
      
      
      def intent(text):
          if not text or not text.startswith("---"):
              return None
          match = re.match(r"^---\s*\n(.*?)\n---(?:\s*\n|$)", text, re.S)
          if not match:
              return None
          lines = match.group(1).splitlines()
          for index, line in enumerate(lines):
              found = re.match(r"^intent:\s*(.*)$", line)
              if not found:
                  continue
              value = found.group(1).strip()
              if value in {"|", ">", "|-", ">-", "|+", ">+"}:
                  block = []
                  for later in lines[index + 1:]:
                      if later and not later[0].isspace():
                          break
                      block.append(later.strip())
                  return " ".join(part for part in block if part)
              if len(value) >= 2 and value[0] == value[-1] and value[0] in {"'", '"'}:
                  if value[0] == '"':
                      try:
                          return json.loads(value)
                      except json.JSONDecodeError:
                          pass
                  return value[1:-1]
              return value or None
          return None
      
      
      def light_learned(text):
          if not text:
              return ""
          body = re.sub(r"^---\s*\n.*?\n---\s*\n", "", text, count=1, flags=re.S).strip()
          if len(body) <= 800:
              return body
          boundary = body.rfind("\n", 0, 800)
          return body[:boundary if boundary > 0 else 800].rstrip() + "\n[… use --depth full for the rest]"
      
      
      def render_topology(start, root, depth):
          output = ["## TOPOLOGY TRACE", f"root: {root}", f"start: {start}"]
          nodes, error = ascent(start, root)
          if error:
              return "\n".join(output + [f"TRACE GAP — {error}"])
          for node in nodes:
              chain_file = node / "LEARNED.md"
              text = read(chain_file)
              label = node.relative_to(root) or Path(".")
              if text is None:
                  output.append(f"\n### {label}\nMISSING LINK — {chain_file}")
                  continue
              body = text.strip() if depth == "full" else light_learned(text)
              output.append(f"\n### {label} · LEARNED.md\n{body}")
          return "\n".join(output)
      
      
      def render_work(start, root, depth):
          output = ["## WORK TRACE", f"root: {root}", f"start: {start}"]
          nodes, error = ascent(start, root)
          if error:
              return "\n".join(output + [f"TRACE GAP — {error}"])
          for node in nodes:
              label = node.relative_to(root) or Path(".")
              spec = next((candidate for candidate in (node / "SPEC.md", node / "README.md") if candidate.is_file()), None)
              if spec is None:
                  output.append(f"\n### {label}\nMISSING LINK — no SPEC.md or README.md at {node}")
              else:
                  text = read(spec) or ""
                  if depth == "full":
                      body = text.strip()
                  else:
                      value = intent(text)
                      body = f"intent: {value}" if value else "MISSING INTENT — no readable intent: field"
                  output.append(f"\n### {label} · {spec.name}\n{body}")
      
              notes, resolution_error = resolve_notes(node)
              if resolution_error:
                  output.append(f"NOTES RESOLUTION GAP — {resolution_error} at {node}")
              elif notes:
                  notes_path, notes_name = notes
                  if depth == "full":
                      notes_text = read(notes_path)
                      if notes_text is None:
                          output.append(f"NOTES RESOLUTION GAP — resolved {notes_name} became unreadable at {notes_path}")
                      else:
                          output.append(f"\nNOTES · {notes_name}\n{notes_text.strip()}")
                  else:
                      try:
                          size = notes_path.stat().st_size
                      except OSError:
                          output.append(f"NOTES RESOLUTION GAP — resolved {notes_name} became unreadable at {notes_path}")
                      else:
                          output.append(f"NOTES · {notes_name} · {size} bytes · {notes_path}")
              else:
                  output.append(f"NOTES GAP — no readable mission notes at {node}")
          return "\n".join(output)
      
      
      def derive_topology_start(root):
          explicit = os.environ.get("OPENRIG_REFOCUS_TOPOLOGY_NODE")
          if explicit:
              return Path(explicit)
          raw = rig_output("whoami", "--json")
          if not raw:
              return None
          try:
              identity = json.loads(raw).get("identity", {})
          except json.JSONDecodeError:
              return None
          rig = identity.get("rigName")
          session = identity.get("sessionName")
          if not rig or not session:
              return None
          seat = str(session).split("@", 1)[0]
          return root / "rigs" / str(rig) / "seats" / seat
      
      
      def derive_work_start(root):
          explicit = os.environ.get("OPENRIG_REFOCUS_WORK_NODE")
          if explicit:
              return Path(explicit)
          current = Path.cwd().resolve()
          if not under_root(current, root):
              return None
          while under_root(current, root):
              if (current / "SPEC.md").is_file() or (current / "README.md").is_file():
                  return current
              if current == root:
                  break
              current = current.parent
          return None
      
      
      def main():
          parser = argparse.ArgumentParser(description=__doc__)
          parser.add_argument("--trees", choices=("topology", "work", "both"), default=os.environ.get("OPENRIG_REFOCUS_TREES", "both"))
          parser.add_argument("--depth", choices=("light", "full"), default=os.environ.get("OPENRIG_REFOCUS_DEPTH", "light"))
          parser.add_argument("--topology-start")
          parser.add_argument("--work-start")
          args = parser.parse_args()
      
          sections = []
          if args.trees in {"topology", "both"}:
              root = configured_root("topology.root", "OPENRIG_TOPOLOGY_ROOT")
              if root is None:
                  sections.append("## TOPOLOGY TRACE\nTRACE GAP — topology.root is unresolved")
              else:
                  start = Path(args.topology_start) if args.topology_start else derive_topology_start(root)
                  sections.append(render_topology(start, root, args.depth) if start else
                                  "## TOPOLOGY TRACE\nTRACE GAP — current topology node is unresolved; set OPENRIG_REFOCUS_TOPOLOGY_NODE")
      
          if args.trees in {"work", "both"}:
              root = configured_root("workspace.root", "OPENRIG_WORKSPACE_ROOT")
              if root is None:
                  sections.append("## WORK TRACE\nTRACE GAP — workspace.root is unresolved")
              else:
                  start = Path(args.work_start) if args.work_start else derive_work_start(root)
                  sections.append(render_work(start, root, args.depth) if start else
                                  "## WORK TRACE\nTRACE GAP — current work node is unresolved; set OPENRIG_REFOCUS_WORK_NODE")
      
          print("\n\n".join(sections))
          return 0
      
      
      if __name__ == "__main__":
          raise SystemExit(main())
      
  • SKILL.md 1.4 KB
    ---
    name: refocusing
    description: >-
      Use when a long-running agent may have lost the product outcome, when context was compacted,
      when work has crossed a major boundary, or when a fresh path-based trace is needed before the
      next consequential action. Not for fresh-session orientation, waking an idle seat, or checkpoints.
    metadata:
      openrig:
        stage: product
    ---
    
    # Refocusing
    
    Refocus preserves a long session's earned expertise while re-grounding it in current intent and
    lived context. It is not a restart, wake, or phase checkpoint.
    
    Run the bundled trace from this skill directory instead of reconstructing the hierarchy from memory:
    
    ```bash
    python3 scripts/trace-to-root.py --trees both --depth light
    ```
    
    Use `--trees topology|work|both` to select context domains and `--depth light|full` to control how
    much each node contributes. Light work traces compose `intent:` and name notes; full traces include
    the complete node and notes bodies. The script resolves `topology.root` and `workspace.root` with
    `rig config get`. When a current node cannot be derived, set `OPENRIG_REFOCUS_TOPOLOGY_NODE` or
    `OPENRIG_REFOCUS_WORK_NODE`, or pass the matching `--*-start` option.
    
    Read [references/refocus.md](references/refocus.md) when changing the automatic hook or its content
    ladder. A missing chain file is evidence: report the gap and continue; never follow pointers to invent
    a second parent.
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related