소스 정보
- 저장소
- agent-sh/skillers
- 최근 소스 활동
- 2026년 4월 26일 15:20
- 감지된 SKILL.md 언어
- 영어
- 스타
- 3
- 포크
- 1
설치 방법
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
소스 파일 검토
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
메뉴
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/agent-sh/skillers --skill skillers-compact명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
SOC 직업 분류 기준
SKILL.md 표시 중
| name | skillers-compact |
| description | Compact conversation transcripts into themed knowledge files. |
| version | 0.2.0 |
| argument-hint | --scope=repo|global|both --state-dir=PATH --days=N |
Invoked by the skillers-compactor agent during /skillers compact. Also usable standalone for manual compaction.
Parse from $ARGUMENTS:
| Flag | Values | Default | Description |
|---|---|---|---|
--scope | repo, global, both | global | Which knowledge scope to write to |
--state-dir | path | (from platform) | Override state directory |
--days | number | 7 | How many days of transcripts to analyze |
Skillers reads conversation transcripts from multiple AI tools. Detect which tools are installed and read from all available sources.
Location: ~/.claude/projects/{project-hash}/{session-id}.jsonl
The project hash is derived from the CWD with path separators replaced by dashes. Each transcript is a JSONL file with entries of type: user, assistant, system, progress, file-history-snapshot.
{
"type": "user",
"message": { "role": "user", "content": "the user message" },
"timestamp": "2026-03-09T14:25:05.135Z",
"sessionId": "uuid",
"cwd": "/path/to/project"
}
Location: ~/.codex/sessions/{YYYY}/{MM}/{DD}/rollout-{timestamp}-{uuid}.jsonl
Sessions are organized by date. Each JSONL file starts with a session_meta entry, followed by response_item and event_msg entries. User messages have type: "event_msg" with payload.type: "user_message".
{"timestamp":"...","type":"session_meta","payload":{"id":"uuid","cwd":"...","cli_version":"0.77.0"}}
{"timestamp":"...","type":"event_msg","payload":{"type":"user_message","message":"the user message"}}
{"timestamp":"...","type":"response_item","payload":{"type":"message"
Also available: ~/.codex/history.jsonl - compact log with only user inputs per session:
{"session_id":"uuid","ts":1767723836,"text":"the user message"}
Location: ~/.local/share/opencode/opencode.db (SQLite)
Tables: project, session, message. Query sessions and messages with SQL.
SELECT s.id, s.slug, m.time_created, m.content
FROM session s JOIN message m ON m.session_id = s.id
WHERE m.time_created > {cutoff_timestamp}
ORDER BY m.time_created;
Also available: ~/.local/state/opencode/prompt-history.jsonl - user input history only:
{"input":"the user message","parts":[],"mode":"normal"}
On Windows the DB may also be at %APPDATA%/opencode/opencode.db.
Cursor and Kiro do not store conversation history in an accessible local format. Skip during compaction.
const os = require('os');
const path = require('path');
const fs = require('fs');
const STATE_DIR = process.env.AI_STATE_DIR || '.claude';
const scope = args.scope || 'global';
const days = args.days || 7;
// Knowledge output directories
const globalDir = path.join(os.homedir(), STATE_DIR, 'skillers', 'knowledge');
const repoDir = path.join(process.cwd(), STATE_DIR, 'skillers', 'knowledge');
const knowledgeDirs = scope === 'both' ? [globalDir, repoDir]
: scope === 'global' ? [globalDir] : [repoDir];
const sources = [];
const claudeDir = path.join(os.homedir(), '.claude', 'projects');
if (fs.existsSync(claudeDir)) sources.push({ tool: 'claude-code', type: 'jsonl', path: claudeDir });
codexDir = path.(os.(), , );
(fs.(codexDir)) sources.({ : , : , : codexDir });
opencodePaths = [
path.(os.(), , , , ),
path.(process.. || , , )
];
( p opencodePaths) {
(fs.(p)) { sources.({ : , : , : p }); ; }
}
For each detected source, collect transcripts using the appropriate method:
Claude Code (JSONL):
~/.claude/projects/.jsonl transcript files--days daystype: "user" and type: "assistant"Codex CLI (JSONL):
~/.codex/sessions/{YYYY}/{MM}/{DD}/ date directories.jsonl files within the date rangesession_meta for session context (cwd, cli_version)event_msg entries with payload.type: "user_message" for user messagesresponse_item entries with payload.role: "assistant" for tool usage patternsOpenCode (SQLite):
opencode.db with a SQLite reader (Bash: sqlite3 or node better-sqlite3)message table joined with sessionCommon for all sources:
lastCompactedAt - skip already-processed transcriptssource: "claude-code" | "codex" | "opencode" for traceabilitylib/sanitize.js::redact()
from the skillers plugin root. Users commonly paste API keys, GitHub tokens,
AWS keys, and Bearer tokens into chat; those must not enter agent context
or persisted knowledge files.const path = require('path');
const { redact } = require(path.join(PLUGIN_ROOT, 'lib', 'sanitize'));
function readJsonlSafe(filePath) {
const raw = fs.readFileSync(filePath, 'utf8');
return raw.split('\n').filter(Boolean).map(line => {
const safeLine = redact(line);
try { return JSON.parse(safeLine); } catch { return null; }
}).filter(Boolean);
}
For OpenCode SQLite, apply redact() to each message.content string after
fetching rows and before extracting observations.
For each transcript, analyze the conversation to identify:
| Type | Signal | Example |
|---|---|---|
pain | User expresses frustration, mentions something failing, retries | "this broke again", "why does X keep happening" |
repeat | User asks for the same type of task across sessions | "run tests", "check CI", "create PR" |
task | User works on a recurring task type | "refactor auth", "update docs", "fix flaky test" |
wish | User expresses desire for automation or tooling | "I wish this was automatic", "there should be a command for this" |
workflow | User follows a consistent multi-step pattern | "first X, then Y, then Z" every time |
For each identified pattern, create an observation:
{"ts": "ISO timestamp", "t": "pain|repeat|task|wish|workflow", "v": "5 word description", "ctx": "file or area", "session": "session-id", "source": "claude-code|codex|opencode"}
Extract observations based on actual conversation content. Focus on:
Do NOT create observations for:
Group observations by semantic similarity:
v and ctx fields (lowercase, split on spaces and path separators)For each theme cluster, calculate a composite weight:
function calculateWeight(observations) {
const now = Date.now();
// Frequency: more observations = higher weight
const frequency = Math.min(observations.length / 20, 1.0); // Cap at 20
// Recency: recent observations weigh more (exponential decay, 30-day half-life)
const recencyScores = observations.map(obs => {
const ageMs = now - new Date(obs.ts).getTime();
const ageDays = ageMs / 86400000;
return Math.exp(-0.693 * ageDays / 30); // 0.693 = ln(2)
});
const recency = recencyScores.reduce((a, b) => a + b, 0) / observations.length;
// Cross-session: patterns across multiple sessions weigh disproportionately more
const sessions = new Set(observations.map(obs => obs.session));
const crossSession = Math.min(sessions. / , );
painCount = observations.( obs. === || obs. === ).;
painBoost = painCount > ? + (painCount / observations.) * : ;
raw = (frequency * + recency * + crossSession * ) * painBoost;
.(.(raw, ) * ) / ;
}
For each theme:
knowledge/{theme-name}.json already existslastSeen and sessions countKnowledge file format:
{
"theme": "ci-pr-workflow",
"weight": 0.82,
"observations": [
{"ts": "...", "t": "repeat", "v": "create PR check CI", "ctx": "github", "session": "abc", "source": "claude-code"},
{"ts": "...", "t": "workflow", "v": "merge after CI pass", "ctx": "github", "session": "def", "source"
Remove entries that are:
After successful compaction, update the skillers config:
{
"lastCompactedAt": "2026-03-09T22:30:00.000Z",
"lastTranscriptsProcessed": ["session-id-1", "session-id-2"]
}
This prevents re-processing the same transcripts on next compact.
Return JSON summary to the calling agent:
{
"sources": {
"claude-code": {"transcripts": 12, "observations": 35},
"codex": {"transcripts": 8, "observations": 12},
"opencode": {"sessions": 3, "observations": 5}
},
"totalTranscripts": 23,
"totalObservations": 52,
"themesUpdated": 2,
"themesCreated": 1,
"themesPruned":