AiTools.ProfileSyncTool 1.0.0.327
profile-sync-tool
Catalog agent-config servisinden profil çekip consumer'lara (.claude/rules vb.) dağıtan dotnet tool
(T#682). apps/sync-ai-configs'ın yerini alır: dosya-okuma + .sync.json/.workspace.json registry yok;
kaynak catalog snapshot, render client-side.
Sıfır lib/registry bağımlılığı (Spectre.Console + System.Text.Json + System.Net.Http).
Kavramsal model + akış şeması (agent-facing): KB domain doc
projects/ai-tools/profile-sync/consumer-flow.md(topicprofile-sync). Bu README kurulum/çalıştırma için developer-canonical; akış/auth modeli/claude-desktop gotcha'ları için domain doc canonical.
Nasıl çalışır
GET /api/agent-config/snapshot→ atoms (roles + instruction groups/shards + skills + profiles).- Client-side resolve (
ProfileResolver): selector → 4-seviye fallback match → audience-filtreli denormalize. ServerResolveProfileAsyncalgoritmasının birebir portu; drift parity test ile korunur. - Render (
ProfileRenderer+InstructionEmitter): ResolvedProfile → editör formatı (claude-code:.claude/rules/*.md).
Auth — PAT (primary) / session-id (fallback)
Gateway üzerinden iki yöntem (gateway ikisini de kabul eder):
- PAT (primary):
Authorization: Bearer ts_pat_v1_*. - session-id (fallback):
x-session-id: <GUID>(catalog-loader paterni).
snapshot/resolve allowAuthenticated (admin değil) → read-only yeterli. Tool catalog'a doğrudan değil,
gateway'e gider. Env yoksa interaktif prompt: önce yöntem (pat | session-id), sonra değer (gizli).
Kullanım
dotnet tool install --global AiTools.ProfileSyncTool
export PROFILE_SYNC_API_BASE="https://<gateway>/api"
export PROFILE_SYNC_PAT="ts_pat_v1_..."
profile-sync # interaktif wizard
profile-sync --dry-run # yazma yok, plan
# Headless (non-interactive) — conductor / script (T#688):
profile-sync prepare --role governance --editors claude-code --target-dir ./repo --api-base https://<gateway>/api --pat ts_pat_v1_...
profile-sync prepare --help # tum flag'ler + exit kodlari (0 ok / 1 catalog-resolve-ag / 3 kullanim)
prepare alt-komutu interaktif wizard'i BYPASS eder (TTY gerekmez); selector + auth flag'lerden kurulur (auth: flag > env, pat > session). Alt-komut yoksa interaktif mod DEFAULT.
Wizard sırası (data-driven)
modelTier (Faz 1: frontier) → role → workType? → scope|stack? → hedef dizin (boş = CWD) → editör hedefleri
(multiselect: cursor / claude-code / trae / codex / claude-desktop). Seçenekler snapshot.Profiles'tan türetilir (var olmayan tuple sunulmaz).
T#690: claude-desktop artık editör listesinde (ayrı toggle yok); seçilirse global config + <hedef>/.claude-desktop prompt dizini.
| Env / flag | Açıklama |
|---|---|
PROFILE_SYNC_API_BASE |
Gateway API kökü (örn. https://host/api). Yoksa prompt. |
PROFILE_SYNC_PAT |
PAT (ts_pat_v1_...). Opsiyonel — primary. |
PROFILE_SYNC_SESSION |
Session id (GUID). Opsiyonel — PAT yoksa fallback. |
--dry-run |
Yazma yok, sadece plan + sayım. |
--help |
Kullanım. |
Auth çözümü: env'de PAT varsa Bearer; yoksa session varsa x-session-id; ikisi de yoksa prompt (yöntem + değer).
Claude Desktop hedefi
File-tabanlı editörlerden (cursor/claude-code/…) ayrıdır: Claude Desktop instruction .md'lerini bir klasörden
otomatik okumaz. Bu hedef iki şey üretir:
- Global MCP config →
%APPDATA%/Claude/claude_desktop_config.json(macOS:~/Library/Application Support/Claude/…, Linux:~/.config/Claude/…). Mevcut server'lar ve diğer key'ler korunur (merge), yazmadan önce.bak.1..3yedeği alınır. - Prompt dizini → seçtiğin klasöre
{role}-instruction.md+skills/<name>/…(manuel yükleme için).
Neden stdio-bridge (streamable-HTTP değil)?
Claude Desktop config şeması yalnızca stdio doğrular; gateway'in streamable-HTTP URL'ini doğrudan yazarsan sessizce
düşürür. Bu yüzden MCP, npx mcp-remote ile sarmalanır. Remote Custom Connector (Settings → Connectors) bir alternatiftir
ama (a) dosyaya yazılamaz, UI'dan eklenir, (b) Anthropic cloud'undan bağlanır → private gateway'e erişemez. Bu yüzden tool
dosya-emit edilebilen stdio-bridge'i kullanır.
Auth: env-ref + env bloğu
Auth değeri args'a inline gömülmez; Authorization:${PROFILE_SYNC_MCP_AUTH} referansı + server'ın env bloğunda değer
yazılır. mcp-remote ${VAR}'ı process env'den çözer (canlı doğrulandı — log: "Replacing $ with
environment value"). Değer env bloğundan gelir; Claude Desktop bu bloğu spawn ettiği child process'e geçirir.
Not (canlı e2e dersi): OS environment variable yolu (config'e değer yazmadan
setxile) Claude Desktop'ta çalışmaz — Desktop,setx'lenen OS env'i full re-login olmadan child'a geçirmiyor. Bu yüzden değerenvbloğunda taşınır. Rotation =envalanını düzenle veya tool'u yeniden çalıştır.
Kullanım
claude-desktop artık editör listesinden seçilir (T#690 — ayrı toggle yok); prompt dizini sabit: <hedef>/.claude-desktop.
profile-sync --dry-run # ÖNCE: merge önizlemesini gör (global config'e dokunmaz)
profile-sync # wizard → editör hedefleri'nde "claude-desktop"u işaretle
# Headless:
profile-sync prepare --role <r> --editors claude-desktop --api-base ... --pat ...
Sonra Claude Desktop'ı yeniden başlat → agent-ops + knowledge-base server'ları MCP listesinde görünür.
Prompt dizinindeki {role}-instruction.md'yi bir Claude Desktop Project'ine elle ekleyebilirsin.
Uyarı (auth): Global config auth'u
envbloğunda gömülü taşır — bu dosyayı paylaşma. Operatör session-id ile auth olduysa MCP runtime'a session gömülür ve expire olunca bağlantı kopar → kalıcı kullanım için PAT önerilir (role-scoped PAT-store: T#684). Config global olduğu için server adları sabittir (agent-ops/knowledge-base); her sync son seçilen rolü yazar (aynı anda tek aktif rol).
local-compose hedefi (T#718 Faz 3)
File-tabanlı editörlerden ve claude-desktop'tan ayrı üçüncü şekil: ambient instruction dosyaları yerine
composer-tüketilebilir tek yapısal manifest üretir. Local model prompt kompozisyonu içindir — conductor
LocalPromptComposerService bu manifesti okuyup faz-scope'lu prompt'a gömer (ambient CLAUDE.md local tier'da RED;
ADR local-frontier-task-boundary §8).
# Headless (conductor'ın çağırdığı şekil; model-tier local zorunlu değil ama beklenen kullanım):
profile-sync prepare --role governance --model-tier local --editors local-compose --target-dir <dir> --api-base ... --pat ...
Çıktı: {targetDir}/.local-compose/context.json — şema (schemaVersion: 1):
{
"schemaVersion": 1,
"role": "governance",
"instruction": "<çözülen profilin monolithic instruction blob'u>",
"skills": [
{
"name": "task-flow-local",
"description": "...",
"body": "<SKILL.md gövdesi>",
"references": [ { "path": "references/x.md", "body": "..." } ]
}
]
}
Sorumluluk sınırı: emitter TÜM çözülen içeriği yazar (audience-filtreli — local profil = local skill seti);
faz-scope seçim composer'a aittir (conductor PromptComposer, Whole|PhaseScoped). Probe-gate kararı
(record/evidence/t718-p5-composition-gate): frontier gövdesi ÇEKİLMEZ, LLM-distilasyon motoru YOK.
docker-unaware: targetDir conductor DataDir cache'i olabilir; pattern-job sandbox'ına mount edilmez.
Manifest dosya sözleşmesi tek bağdır — conductor bu paketi kod olarak referans etmez (process + dosya).
Kapsam
frontier + local · çoklu editör (cursor/claude-code/trae/codex/claude-desktop/local-compose) + headless prepare (T#688) · skills dağıtımı (.../skills/<name>/SKILL.md+refs) ·
mcp config (gateway base'den türetilir, kimlik header gömülü — commit etmeyin) · Claude Desktop (stdio-bridge global
MCP + prompt dizini, Mod A/B auth) · hedef dizin opsiyonel (CWD). project-context: yok (drop kararı; catalog shard'ları
proje-agnostik). cowork: ertelendi (gerekirse ayrı faz). Faz 3: sync-ai-configs retire + server klasör modeli kaldırma.
Test
dotnet test profile-sync-tool.slnx
# Canlı parity (opt-in): PROFILE_SYNC_API_BASE + PROFILE_SYNC_PAT set edilirse
# client resolve == server /profiles/resolve tüm profillerde doğrulanır.