Teknik sunum · MVP · Ekim 2026
OpenTAG: şirket IT ekipleri için yapay zekâ destekli IT destek asistanı
IT çalışanı sorunu Türkçe anlatır. Asistan şirketin sistemlerine şirketteki agent'lar üzerinden bağlanır, teşhis eder, değişikliği planlar ve preview'ını çıkarır, onay alınca uygular ve sonucu doğrular. Yönetim bizde, yetki ve veri şirkette.
- Durum
- Faz 1 tamamlandı, kabul senaryosu canlıda geçti
- Sırada
- Faz 2: onay, imzalı approval ticket, secret store
- Teknoloji
- Go platform ve agent, Next.js console, OpenCode fork
- Son release
- v0.1.5 · macOS, Windows, Linux paketleri
Gezinme: soldaki bölüm listesi, klavyede j / → sonraki bölüm, k / ← önceki bölüm, + projeksiyon için büyük yazı. Bu sayfadaki her ifade bugünkü kod için doğrudur ya da planlanan fazıyla işaretlidir.
02 · Problem ve yaklaşım
IT ekibi çok sayıda farklı sistemi yönetir; bilgi dağınık, değişiklik risklidir
Problem
- Linux ve Windows sunucular, Kubernetes, veritabanları, HTTP API'ler ve e-posta aynı ekibin sorumluluğundadır. Her birinin komutları ve tuzakları ayrıdır.
- Yöntem bilgisi kişilerde kalır; giriş seviyesindeki IT çalışanı riskli işlerde kıdemli birine bağımlıdır.
- Genel amaçlı AI sohbetleri sistemlere dokunamaz: komut ve çıktılar elle kopyalanır, parolalar sohbete yapıştırılır.
- Sınırsız shell yetkisi verilen bir AI agent ise onay, audit ve secret koruması olmadan çalışır.
Yaklaşım
- Agent'lar şirkette çalışır. Tool'lar ve secret'lar IT çalışanının bilgisayarında ve şirket sunucusunda durur; platform müşteri sistemine kendisi dokunmaz.
- Önce oku, sonra planla ve onayla yaz. Her write tool hedef, etki, rollback ve doğrulama içeren bir plan ister; mümkünse önce preview yapılır.
- Secret değerleri modele ulaşmaz. Model yalnız
secret://referansı görür, çıktılar maskelenir. - Generic core. Ürüne özel kod yoktur; yeni bir sistem çoğu zaman yalnız bir skill'dir.
- Öğrenen sistem. Çözülen sorun skill olarak kaydedilir ve şirket içinde paylaşılır.
Kimin için
| Role (Zitadel project role) | Ne yapar |
|---|---|
sirket_admini | Şirketin admini: agent kurulum token'ı üretir, server agent'ları yönetir; Faz 2-3 ile shared connection'lar, policy, üyeler ve MCP server'lar. Bütün role kontrollerini geçer. |
kidemli_it | Kıdemli IT: skill'leri şirket içinde paylaşır (Faz 3 kuralı), audit log'u görür (Faz 4). |
it | IT çalışanı: sohbetle çalışır. Role'üne kapalı capability'ler (ör. script) şirket policy'siyle kısıtlanır (Faz 2). |
03 · Bugün ve plan
Neler çalışıyor, neler planlı
Bugün çalışan Çalışıyor
- macOS, Windows ve Linux masaüstü paketleri; portaldan PC enrollment ve revoke.
- Chat UI (OpenCode fork) ve PC'de
opentagd: Kubernetes, SSH, PostgreSQL, HTTP API, SMTP, script ve Ansible tool'ları. - Zorunlu plan, k8s ve SQL için preview, secret masking, guard plugin, local audit log.
- Platform: Postgres ve RLS, Zitadel role'leri, agent enrollment (
pcvesite), WSS gateway, job queue, LLM proxy, skill repo. - Server agent:
opentagd install --server(systemd, Windows service, Docker image). - PC'deki AI, server agent'taki bir connection'da tool'u platform job'ı olarak çalıştırır; connection'lar birleşik listede görünür.
Planlı Faz 2-4
- Faz 2: policy, console'da onay, imzalı tek kullanımlık approval ticket, agent'ta local allowlist, age secret store ve recovery key, console'dan şifreli secret girişi, PowerShell tool'ları.
- Faz 3: console relay (tarayıcı
127.0.0.1'e gitmez), console'da chat, skill kartlarından oluşan Katalog sayfası, MCP repo ve aggregator, üyeler ve davet, LiteLLM limitleri. - Faz 4: scheduled job'lar ve standing approval, platformda audit summary, Google, n8n ve merkezi entegrasyon kodunun kaldırılması, failure testleri, pilot kurulum belgesi.
- MVP dışı ürüne özel entegrasyonlar, template/workflow engine, platformun müşteri sunucusuna kurulumu, OpenBao ve kısa ömürlü SSH sertifikası, code signing ve auto-update, SIEM ve SCIM, merkezi sohbet arşivi.
Geçiş dönemi notu: Google hesabı bağlama ve n8n akışları ilk sürümden kalmadır ve bugün kodda durur. Generic core kararıyla (15 Ekim) bırakıldı; Faz 4'te kaldırılır (issue #44-#48).
04 · Mimari
Üç parça: platform, PC agent, server agent
Platform bizim sunucumuzda, multi-tenant çalışır. Her agent platforma outbound tek bir WSS connection (443) açar; şirkette port açmak ya da VPN kurmak gerekmez. Job'ı, connection'ın durduğu agent çalıştırır.
127.0.0.1:4747/llm/v1/* → platform /v1/llm/v1/* (device token) → LiteLLM (kullanıcının virtual key'i).İlkeler
- Connection'ı her zaman agent açar. WSS connection üç şey taşır: job queue, console relay (Faz 3) ve config değişikliği bildirimleri.
- Queue Postgres'te. Lease, ACK ve redelivery; sonucu belirsiz kalan write job tekrarlanmaz.
- AI her zaman PC'deki OpenCode'dan çağırır. Hedef connection server agent'taysa çağrı platform üzerinden job olarak oraya gider.
- Single-tenant kurulum engellenmez. Aynı image, config env'den, her tabloda
tenant_id. Müşteri sunucusuna kurulum MVP sonrasıdır.
05 · Bileşenler
Her bileşen: görev, teknoloji, veri, arayüz
Platform
platform/ · GoGo (stdlib net/http) tek servis, api.opentag.nesiler.com. k3s'te opentag-backend namespace'i, tek replica.
- Zitadel JWT doğrulama (JWKS,
iss,aud); tenant = Zitadel org id, ilk görüldüğünde oluşur. Client'tan gelen tenant bilgisine güvenilmez. - Enrollment kodu (10 dk, tek kullanım), device token (90 gün, DB'de sha256), local access token (Ed25519 JWT, 12 saat) ve
/.well-known/jwks.json. - Agent'lar (
kind=pc|site), kurulum token'ı, WSS gateway,jobsqueue (agent başına aynı anda en çok 8 job). - LLM proxy: LiteLLM'e buffer'sız reverse proxy; kullanıcı başına virtual key ilk çağrıda üretilir ve izinli modellerle sınırlıdır. LiteLLM master key yalnız platformdadır.
- Skill repo (central ve shared, integer version, ≤ 256 KB, secret pattern taraması).
- Log'a yalnız method, path, status ve süre yazılır; token, kod ya da anahtar yazılmaz.
- Faz 2-4 policy, onaylar ve ticket imzalama, shared connection endpoint'leri, relay, MCP repo, üyeler, limitler, scheduler, audit summary.
Postgres
postgres:16-alpine- Tek instance, 10 Gi persistent volume; her gece 02:30'da
pg_dumpCronJob'u (ayrı 5 Gi backup volume'u). Restore denemesi Faz 4'te (4.7). - goose migration'ları startup'ta uygulanır (
00001_init,00002_agents,00003_jobs). SQLite'tan geçildi; yalnız Postgres desteklenir. - Tenant izolasyonu RLS ile: tablolar
ENABLE+FORCE ROW LEVEL SECURITY, policytenant_id = app_tenant(); her DB connection'ındaSET app.tenant_id. - Backend superuser değildir:
opentag_approle'ü (BYPASSRLS yok). Superuser yalnız yönetim ve backup içindir.
Portal ve console
portal/ · Next.js- Next.js 16 (App Router), React 19, Tailwind 4, next-auth 5 (Zitadel OIDC, PKCE).
opentag.nesiler.com. - Backend çağrıları yalnız server tarafında; Zitadel token'ı tarayıcıya verilmez.
- Bugünkü sayfalar: tanıtım, genel bakış (indirme, eşleştirme, cihazlar), Ajanlar (kurulum token'ı, online durumu), bağlantılar, skill'ler, entegrasyonlar (Faz 4'te kalkar).
- Faz 3 console: AI SDK
useChatve relay üzerinden çalışan kendi OpenCode transport'u, AI Elements, streamdown; JSON Schema'dan formlar (react-hook-form + Ajv); next-intl. Ekranlar: starter kartları, chat ve onay kartı, onay bekleyenler, agent'lar, connection'lar ve secret girişi, skill'ler, MCP server'lar, scheduled job'lar, üyeler, policy, usage, audit.
PC agent
agent/ · opentagd- Tek Go binary'si; PC modunda yalnız
127.0.0.1:4747'de dinler. Host loopback değilse ve Origin izinli değilse 403 (DNS rebinding koruması). - OpenCode'u başlatır, çökerse 5 dakikada en çok 5 kez yeniden başlatır. OpenCode'a her başlatmada rastgele üretilen
OPENTAG_LLM_KEY,OPENTAG_MCP_KEYve iç parola verir. /mcp: MCP server (Streamable HTTP). Bütün tool'lar burada; çıktı 20 KB'a kesilir, secret'lar maskelenir, her çağrıaudit.log'a yazılır.- Connection'lar: secret olmayan alanlar
connections.yaml'da, secret'lar Keychain / Credential Manager'da (uzun değerler 1000 baytlık parçalara bölünür). - Tool routing: başka agent'taki connection'da her tool, kişisel connection'da yalnız write tool'lar platform job'ı olur.
- Heartbeat 60 sn; platform
401 device_revokedderse token silinir ve bütün endpoint'ler 403 döner.
Server agent
opentagd --server- Aynı binary, server modunda: OpenCode başlatılmaz, yerel port açılmaz. Veri dizini
/var/lib/opentagya da%ProgramData%\OpenTag. opentagd install --server --token <ota_…>: enrollment, device token'ı0600dosyaya, Linux'ta systemd system service, Windows'ta otomatik başlayan service. Docker image da var (OPENTAG_ENROLL_TOKEN).- Linux paketinde ansible ve uv bulunur; Windows server agent'ta Ansible tool'ları yoktur.
- Biten job'lar
jobs-done.json'da (son 200) tutulur; aynıjob_idgelirse tool yeniden çalışmaz. - Bugün secret girişi sunucuda
opentagd secret setile (stdin'den,0600dosya). Faz 2 age ile şifreli secret store, key Windows'ta DPAPI'de, Linux'ta root'a ait0600dosyada; recovery key, console'dan şifreli giriş.
OpenCode client
client/ · OpenCode fork- OpenCode v2.0.20'nin MIT lisanslı fork'u: runtime ve web UI. Marka, sabit backend adresi, varsayılan proje
~/opentag/work; terminal (PTY) ve upstream'e giden dış bağlantılar kaldırıldı. - Agent'lar:
opentag(ana,deepseek-flash-deepseek) veuzman(read-only subagent,deepseek-pro-deepseek). Yerleşikbuild/plankapalı, yalnızopentagprovider'ı etkin. - Guard plugin (
opentag-guard.js): bash yasakları, argümanlarda düz secret engeli, sohbete inventory ve connection özeti. - Paketle gelen skill'ler ve system prompt Türkçe.
Zitadel
identityOIDC provider. Her müşteri bir org'dur; role'ler project role'leridir ve JWT'deki urn:zitadel:iam:org:project:<id>:roles claim'inden okunur. Access token RS256, 12 saat. Faz 3 davet, role değiştirme, disable etme ve tenant açma script'i.
LiteLLM
ai.nesiler.comModel erişim katmanı. Bugün kullanıcı başına virtual key (opentag:<email>), izinli modeller deepseek-flash-deepseek ve deepseek-pro-deepseek. Faz 3 şirket = LiteLLM team (bütçe, TPM/RPM, izinli modeller), kullanıcı bütçesi, limit aşımında 429 llm_limit_exceeded. Kişisel veri maskeleme ayrı llm-gateway projesinde (LiteLLM + Presidio) paralel yürür.
Ansible
ansible/ · catalog.ymlLinux bakım ve hardening playbook'ları ve catalog'u. macOS ve Linux paketine collection'lar ve role'ler önceden kurulu girer; çalışma anında Galaxy'ye gidilmez. ansible-core 2.21.4 paketteki uv ile pinned version'da çalışır. Ayrıntı: Tool'lar, skill, MCP.
06 · Veri nerede durur
Şirkette kalan, platforma gelen
| Veri | Nerede | Durum |
|---|---|---|
| Kişisel secret'lar | PC agent'ta: bugün OS keystore'unda (Keychain, Credential Manager, Secret Service); Faz 2'de key'i OS keystore'unda duran age dosyası | Çalışıyor |
| Paylaşılan secret'lar | Server agent'ta: bugün 0600 dosya; Faz 2'de age ile şifreli dosya. Platform yalnız adını bilir | Faz 2 store |
| Sohbet geçmişi, ham komut çıktıları | Agent'larda (PC'de OpenCode session'ları, agent'ın audit.log'u ve runs/ dizini) | Çalışıyor |
| Route edilen job'ın argümanı ve sonucu | Platformda jobs tablosunda; sonuç agent'ta maskelenmiş ve 20 KB'a kesilmiş olarak gelir. Argümanda yerel secret değeri varsa job açılmaz (secret_in_args) | Çalışıyor |
| Kullanıcı, role, agent, skill, job durumu | Platformda, tenant'a bağlı (RLS) | Çalışıyor |
| MCP tanımı, policy, onay, audit summary | Platformda; audit yalnız özet: kim, hangi tool, hangi connection, karar, sonuç, çıktının sha256'sı | Faz 2-4 |
| LLM'e giden içerik | LiteLLM üzerinden provider'a gider; secret değerleri tool çıktısında maskelenmiştir. Platform içeriği saklamaz ve log'a yazmaz | Çalışıyor |
| Relay trafiği | Platform iletir, hiçbir yere yazmaz | Faz 3 |
07 · Arayüzler
Platform API, WSS protokolü, MCP tool'ları
Contract docs/api.md'dedir; §7 MVP contract'ıdır (v1). Body'ler JSON, hata biçimi {"error": {"code", "message"}}.
Auth türleri
| Ad | Header | Kim kullanır |
|---|---|---|
| Zitadel | Bearer <Zitadel access token> | Portal (yalnız server tarafı) |
| Device | Bearer otd_… | opentagd (PC ve server agent), HTTPS ve WSS |
| Local | Basic opencode:<jwt> ya da Bearer <jwt> | Tarayıcı → PC'deki opentagd (Faz 3'te relay ile kalkar) |
| Admin | Bearer <OPENTAG_ADMIN_TOKEN> | Admin script'i (central skill upload) |
Platform endpoint'leri
| Endpoint | Auth | Ne yapar | Durum |
|---|---|---|---|
POST /v1/enrollments, POST /v1/devices/enroll | Zitadel / kod | PC enrollment: XXXX-XXXX-XXXX kodu → device token | Çalışıyor |
POST /v1/local-tokens, GET /.well-known/jwks.json | Zitadel / yok | Tarayıcının opentagd'ye gittiği 12 saatlik EdDSA token ve public key | Çalışıyor |
POST /v1/devices/heartbeat | Device | last_seen_at, skills_version | Çalışıyor |
POST /v1/agent-tokens, POST /v1/agents/enroll | sirket_admini / token | Server agent kurulum token'ı (ota_, 24 saat, tek kullanım) ve enrollment | Çalışıyor |
GET /v1/agents, DELETE /v1/agents/{id} | Zitadel | Agent listesi ve online durumu; revoke açık WSS connection'ı kapatır | Çalışıyor |
GET /v1/connections | Device | Tenant'ın server agent'larındaki shared connection'lar (secret değeri yok) | Çalışıyor |
GET /v1/agent/connect | Device | WSS, subprotocol opentag.v1 | Çalışıyor |
POST /v1/jobs, GET /v1/jobs/{id}?wait=, POST /v1/jobs/{id}/cancel | Device / Zitadel | Job oluşturma, long-poll (en çok 120 sn), cancel | Çalışıyor |
ANY /v1/llm/* | Device | LiteLLM'e buffer'sız reverse proxy (SSE) | Çalışıyor |
/v1/skills*, /v1/admin/skills/* | Zitadel / Device / Admin | Liste, içerik, manifest, bundle, paylaşım, central upload | Çalışıyor |
GET/PUT /v1/policy, GET /v1/approvals, POST /v1/approvals/{id} | Zitadel | Policy ve onay; approval endpoint'i yalnız kullanıcı session'ıyla | Faz 2 |
PUT /v1/agents/{id}/connections/{type}/{name} (+ /grants), PUT /v1/agents/{id}/secrets/{name} | sirket_admini | Shared connection ve tarayıcıda age ile şifrelenmiş secret girişi | Faz 2 |
/v1/relay/{agent_id}/* | Zitadel (sahibi) | Console'dan PC agent'a relay; path allowlist | Faz 3 |
/v1/mcp-servers, /v1/members, /v1/invites, /v1/usage, /v1/admin/tenants/{id}/limits | Zitadel / Admin | MCP repo, üyeler, davet, usage, limitler | Faz 3 |
/v1/schedules, GET /v1/audit | Zitadel / Device | Scheduled job'lar, audit summary | Faz 4 |
WSS agent protokolü (opentag.v1)
Her mesaj tek bir JSON frame'dir: {"type": "...", "id": "<ulid>", ...}; bilinmeyen type ignore edilir. Agent 25 sn'de bir ping gönderir; 60 sn sessiz kalan agent offline sayılır, connection'ı kopan agent hemen offline olur. Reconnect 1 sn'den 60 sn'ye kadar artan, jitter'lı backoff ile. Aynı agent yeniden bağlanırsa eski connection kapatılır.
| Yön | type | Alanlar | Durum |
|---|---|---|---|
| A→P | hello | agent_id, kind, version, os, tools[], connections[], mcp_servers[], age_recipient (secret değeri yok) | Çalışıyor |
| P→A | welcome | tenant_id, config_version, ticket_jwks, heartbeat_s | Çalışıyor |
| ↔ | ping / pong | — | Çalışıyor |
| A→P | inventory.changed | connections, mcp_servers | Çalışıyor |
| P→A | job.offer | job_id, attempt, lease_s, tool, connection?, args, ticket?, idempotency_key, deadline | Çalışıyor (ticket Faz 2) |
| A→P | job.ack / job.lease | job_id, attempt; lease'i 30 sn uzatır | Çalışıyor |
| A→P | job.result | job_id, attempt, ok, result, error?, output_sha256, started_at, finished_at | Çalışıyor |
| P→A | job.cancel | job_id | Çalışıyor |
| A→P | job.progress | job_id, seq, text (maskeli) | platform kabul eder; agent henüz göndermez |
| P→A | config.changed | skills_version, mcp_version, policy_version | Faz 3 |
| P→A / A→P | secret.put / secret.ack | tarayıcıda şifrelenmiş secrets_age, connection testi sonucu | Faz 2 |
| ↔ | relay.open / head / data / close | stream_id, method, path, headers, body; base64 chunk'lar | Faz 3 |
| A→P | audit.batch | yerelde çalışan okumaların özeti; offline iken biriktirilir | Faz 4 |
Önemli hata kodları
| Kod | HTTP | Anlam |
|---|---|---|
device_revoked | 401 | Cihaz revoke edilmiş; agent token'ı siler |
enrollment_used / _expired / _invalid | 409 / 410 / 400 | Enrollment kodu ya da kurulum token'ı kullanılmış, süresi dolmuş ya da bilinmiyor |
agent_offline | 409 | Connection'ın agent'ı offline ve son 2 dk içinde görülmedi |
connection_not_found / job_not_found | 404 | Bilinmeyen agent ya da başka tenant'ın job'ı |
plan_required, secret_in_args, secret_host_mismatch | tool hatası | Write tool'da plan eksik; argümanda yerel secret; secret yanlış host'a gidecekti |
pending_approval, denied, ticket_invalid, capability_disabled | 202 / 403 | Faz 2 onay ve policy |
llm_limit_exceeded, requires_server | 429 / 412 | Faz 3-4 LLM limiti; server agent yok |
PC'deki opentagd'nin yerel API'si (/opentag/*, /llm/v1/*, /mcp) ve tool listesi docs/api.md §2-§3'tedir; tool'ların özeti Tool'lar, skill, MCP bölümünde.
08 · Akışlar
Temel akışlar, sequence diagram'larıyla
Düz ok istek, kesikli ok yanıt. Diyagramlar dar ekranda yatay kaydırılır.
1. PC agent enrollment Çalışıyor
2. Server agent kurulumu Çalışıyor
sirket_admini rolüyle alınır (it role'ü 403). Kullanılmış token 409, süresi dolmuş 410 döner. Agent portalın aynı Ajanlar sayfasında online görünür.3. Sohbet → MCP tool → platform job → server agent Çalışıyor
<agent_id>/<type>/<name>; job ilk parçadaki agent'a gider. Kişisel connection'da read tool'lar platforma uğramadan local çalışır; kişisel write job'lar da platform job'ı olur ve aynı PC'ye geri döner (Faz 2'de ticket bu yoldan gelir). PC tarafı sonucu toplam en çok 10 dk bekler.4. Lease, redelivery ve idempotency Çalışıyor
unknown job için geç gelen sonuç da kabul edilir. PC tarafında yarıda kesilen çağrı için cancel istenir; cancel doğrulanamazsa AI'a canceled_unconfirmed döner ve yazmayı tekrarlamadan önce durumu read tool ile kontrol etmesi söylenir.5. Skill sync Çalışıyor
<data dir>/skills/{central,shared}/ altına yazılır ve OpenCode'a OPENTAG_SKILLS_DIR ile verilir; geçersiz path içeren bundle tümüyle reddedilir. Faz 3 config.changed ile değişiklik 1 dk içinde agent'a ulaşır.Planlı akışlar
| Akış | Özet | Faz |
|---|---|---|
| Onaylı write | POST /v1/jobs → policy ask/approval → console'da onay kartı → platform ticket'ı imzalar → job.offer {ticket} → agent ticket'ı ve local allowlist'i doğrular → çalışır | Faz 2 |
| Console'dan secret girişi | Tarayıcı değeri agent'ın age_recipient key'ine şifreler → platform yalnız iletir (secret.put) → agent açar, connection'ı test eder → secret.ack | Faz 2 |
| Console relay | Console /v1/relay/{agent_id}/* → relay.open WSS üzerinden PC agent'a → local OpenCode; SSE stream'leri de bu yoldan, içerik yazılmaz | Faz 3 |
| Scheduled job | AI schedule_create önerir → standing approval → platform zamanı gelince job'ı server agent'a yollar → sonuç console'da | Faz 4 |
09 · Güvenlik modeli
Secret değerleri modele hiçbir zaman ulaşmaz
Tenant izolasyonu Çalışıyor
- Tenant = Zitadel org id; token'dan gelir, client'ın söylediği tenant'a güvenilmez.
- Postgres RLS: her tabloda
tenant_id,FORCE ROW LEVEL SECURITY, DB connection başınaapp.tenant_id. Her sorgu scope'unu connection'a yazarak çalışır; scope'u yazılmamış connection hiçbir satır görmez. Tenant'sız scope yalnız authentication, enrollment, admin ve lease taraması gibi server-side yollardadır. - Backend RLS'i atlayamayan bir role ile bağlanır (
opentag_app, BYPASSRLS yok). - Faz 1 kabulünde ikinci bir tenant'ın kullanıcısı agent'ı, connection'ı ve job'ı göremedi: listeler boş, job/cancel/delete/connection endpoint'leri 404.
Kimlikler ve token'lar
| Token | Üreten → doğrulayan | Ömür | Durum |
|---|---|---|---|
| Zitadel access token (JWT, RS256) | Zitadel → platform (JWKS, iss, aud) | 12 saat | Çalışıyor |
Enrollment kodu XXXX-XXXX-XXXX | Platform → platform | 10 dk, tek kullanım | Çalışıyor |
Kurulum token'ı ota_ | Platform → platform | 24 saat, tek kullanım | Çalışıyor |
Device token otd_ (opaque) | Platform → platform (DB'de sha256) | 90 gün, revoke edilebilir | Çalışıyor |
| Local access token (JWT, EdDSA) | Platform → opentagd (platform JWKS) | 12 saat | Çalışıyor |
OpenCode iç parolası, OPENTAG_LLM_KEY, OPENTAG_MCP_KEY | opentagd → opentagd / OpenCode | process ömrü, her başlatmada rastgele | Çalışıyor |
| LiteLLM virtual key | Platform (kullanıcı başına) → LiteLLM | süresiz; master key kullanıcıya gitmez | Çalışıyor |
| Approval ticket (JWS, EdDSA) | Platform → agent (ticket_jwks) | en çok 10 dk, tek kullanım | Faz 2 |
Komut ve pty process'lerinin environment'ından bu key'ler temizlenir; AI'ın çalıştırdığı child process'ler bu key'leri görmez.
Agent ve client katmanları Çalışıyor
| Katman | Nasıl |
|---|---|
| Form ile giriş | Credential'lar sohbete yazılmaz; model request_connection / request_secret ile portal formunun linkini verir. |
secret:// referansı | Model yalnız secret://<type>/<name>/<field> görür; referans yalnız opentagd içinde çözülür. |
| Secret-host binding | HTTP tool'larında {{secret://…}} yalnız o connection'ın secret'ı ya da hosts listesi hedefi içeren secret için çözülür; aksi halde secret_host_mismatch. Başka host'a ya da https→http'ye redirect takip edilmez. |
| Masking | Bütün connection'ların secret'ları bütün tool çıktılarında ve hatalarda *** olur: düz, JSON, URL-kaçışlı, Python repr, base64, hex. 8 karakterden kısa değerler maskelenmez. Kubernetes Secret değerleri hiç gösterilmez. |
| Değeri dışarı vermeyen tool'lar | k8s_compare_secret_keys yalnız eşit/değil döner; k8s_copy_secret_key ve k8s_set_secret_key değeri opentagd içinde taşır. |
| Plan ve preview | Bütün write tool'lar plan: {hedef, etki, geri_alma, dogrulama} ister. preview_change k8s için dry-run diff, sql_exec için rollback'li çalıştırma yapar. |
| Read-only SSH | ssh_read yalnız allowlist'teki komutları kabul eder; ;, &&, >, $(, sudo reddedilir. Bir filtredir, security boundary değildir. |
| Dosya izinleri | .env, *.pem, *.key, ~/.ssh, ~/.kube, ~/.aws, Keychain'ler ve OpenTAG kurulum dizini OpenCode'da deny. |
| Network | PC'de yalnız 127.0.0.1; Host loopback değilse ya da Origin izinli değilse 403. Server agent hiç port açmaz. |
| SSH host key | İlk bağlantıda pin'lenir (TOFU); sonradan değişirse connection reddedilir. |
| Local audit | Her MCP çağrısı audit.log'a JSON satırı (zaman, tool, connection, maskeli parametreler, sonuç); 5 MB'ta rotate edilir. |
Guard plugin
Guard kullanıcıya yönelik bir filtredir; security boundary Faz 2'de ticket ve agent'ın local allowlist'idir. Bash komutu ;, &&, ||, |, $( ), backtick ve sh -c ile bölünür, her parça ayrı kontrol edilir.
- Yasaklar: tehlikeli
rm -rfhedefleri,sudo/su/doas,dd of=,mkfs,chmod -R 777, indirip çalıştırma (curl … | sh),git push --force,shutdown/reboot, OpenTAG process'lerini kill etme,env/printenvve secret dizinleri. - Bütün tool argümanlarında düz secret pattern'leri (
-----BEGIN, JWT,AKIA,ghp_,sk-,xox[bp]-) engellenir; modelrequest_secret'a yönlendirilir.
Planlı katmanlar
| Konu | Ne gelir | Faz |
|---|---|---|
| Onay ve ticket | Write job yalnız imzalı, tek kullanımlık, 10 dk'lık ticket ile çalışır; agent'ta local allowlist. Ayrıntı: Onay ve policy. | Faz 2 |
| Secret store | age ile şifreli dosya; key DPAPI / root'a ait 0600 dosya / Keychain. Kurulumda bir kez gösterilen recovery key; opentagd secret backup / restore. Sunucuda root'un store'a erişebilmesi bilinçli olarak kabul edildi. | Faz 2 |
| Offboarding | Disable edilen kullanıcının cihazları ve LiteLLM key'i hemen revoke edilir. Bugün cihaz revoke'u portaldan tek tek yapılır. | Faz 3 |
| Audit summary | Platformda yalnız özet (kim, tool, connection, karar, sonuç, çıktı sha256'sı); komut çıktısı ve sohbet agent'ta kalır. | Faz 4 |
| Failure testleri | Network kopması, job ortasında ölen agent, platform restart'ı, ticket replay, süresi dolmuş ticket, yanlış tenant, recovery key ile geri dönüş. | Faz 4 |
10 · Onay ve policy
Onay platformda verilir, agent'ta doğrulanır
Bugün: write tool'lar plan ister ve OpenCode'un permission prompt'unda parametreleriyle kullanıcı onayına düşer (opentag_*: ask). Platform tarafında policy her job'a allow der ve ticket yoktur. Faz 2 ile aşağıdaki model devreye girer ve OpenCode prompt'u opentag tool'larında kapanır; tek onay yeri console'daki onay kartı olur.
Policy Faz 2
Karar şu girdilere bakar: tool, read/write sınıfı, risk, connection label'ı (ör. env=prod) ve role. Kurallar çakışırsa en sıkı karar kazanır.
| Risk | Varsayılan |
|---|---|
none (read) | allow: onay sorulmaz |
medium (write) | ask: isteyen kullanıcı console'da onaylar |
high (run_with_connection, ansible_run) | ask; şirket approval yapabilir (başka kullanıcı onaylar) |
critical | deny |
Şirket, role bazında hangi capability'lerin açık olduğunu seçer; kapalıysa capability_disabled. Self-approval engellenir.
Approval ticket Faz 2
{"iss": "opentag-platform", "tid": "<tenant>",
"aid": "<agent_id>", "jti": "<job_id>",
"tool": "ssh_run", "conn": "<agent_id>/ssh/web-01",
"args_sha256": "<sha256(JCS(args))>",
"decision": "allow|ask|approval|standing",
"approved_by": ["<sub>"], "schedule_id": null,
"iat": 0, "exp": 0}
JWS (EdDSA / Ed25519). Argümanlar RFC 8785 (JCS) ile canonicalize edilip hash'lenir; ticket tool'a, connection'a ve argümanların hash'ine bağlıdır.
Agent write tool'u çalıştırmadan önce
- İmzayı doğrular (
welcome.ticket_jwks,use: ticket). tid,aid,jti,tool,conn,args_sha256alanlarını job'ın kendisiyle karşılaştırır.- Süreyi (
exp) kontrol eder. jti'nin kullanılmadığını kontrol eder ve diske yazar.- Local allowlist'i (
policy.yaml; sunucuda root'a ait,0600, platform değiştiremez) uygular.
Biri tutmazsa ticket_invalid. Approval endpoint'i yalnız Zitadel session'ıyla çağrılır; device token ve MCP key 401 alır, bu yüzden AI kendi job'ını onaylayamaz. Local allowlist bizim sunucumuz ele geçirilse bile geçerlidir.
Standing approval Faz 4
Scheduled job = sabit argümanlı tek bir tool çağrısı ({tool, connection, args, cron, tz}). Standing approval tool + conn + args_sha256'ya bağlıdır, biri değişirse düşer; en çok 90 gün, yalnız risk ≤ medium. Yalnız server agent'ta çalışır; yoksa requires_server.
11 · Tool'lar, skill, MCP
Capability, skill ve MCP server
Core hiçbir ürüne özel kod içermez. Capability: opentagd'nin generic tool'ları. Skill: bilgi ve yöntem (Agent Skills biçimi). MCP server: dışarıdan eklenen tool seti.
Capability'ler
| Capability | Tool'lar | Connection type | Durum |
|---|---|---|---|
linux | ssh_read, ssh_run, ansible_search, ansible_check, ansible_run | ssh | Çalışıyor |
kubernetes | k8s_get|describe|logs|events, k8s_rollout_restart|scale|delete_pod|set_env|trigger_cronjob, k8s_compare|copy|set_secret_key | kubernetes | Çalışıyor |
database | sql_query (READ ONLY, tek ifade, ≤ 200 satır, 30 sn), sql_exec | postgres | Çalışıyor |
http | http_get, http_request | http_api | Çalışıyor |
script | run_with_connection (python / shell, izole çalışma dizini, 60-300 sn) | herhangi | Çalışıyor |
mail | smtp_send | smtp | Çalışıyor |
windows | powershell_read, powershell_run (Windows'un OpenSSH'ı, -EncodedCommand) | ssh (shell: powershell) | Faz 2 |
- Yardımcı tool'lar:
list_connections,request_connection,request_secret,test_connection,define_connection_type,preview_change. - Connection type'ları generic'tir:
ssh,kubernetes,postgres,http_api,smtp,secretve AI'ın tanımladığı type'lar (kullanıcı onaylamadan kullanılamaz). Örneğin Proxmox birhttp_apiconnection'ıdır. - Sınıf ve risk: read
none, writemedium,run_with_connectionveansible_runhigh. Tablonun koda ve MCP annotation'larına geçmesi Faz 2 (2.1).
Skill'ler Çalışıyor
disk-doldu/
├── SKILL.md
├── references/*.md
└── scripts/*.sh | *.ps1 | *.py
- Kaynaklar:
central(biz),shared(yalnız o şirket),local(kullanıcının bilgisayarı). - Paketle gelenler:
ansible,kubernetes,linux-ssh,caddy,headscale,postgres,mail,secrets,runtime,baglanti-tipi-yazma,onboarding,skill-yazma. - AI çözdüğü sorunu skill olarak yazar; kullanıcı şirketle paylaşır. Skill içeriği yalnız talimattır, tool'ların onay kurallarını değiştiremez.
Faz 3 skill frontmatter'ındaki metadata starter kartlarını ve Katalog'u üretir; template engine yoktur, rehberli iş skill'dir.
---
name: disk-doldu
description: Linux sunucuda disk dolduğunda ...
metadata:
opentag.requires: linux
opentag.category: linux
opentag.card: Diski dolan sunucuda yer açar
opentag.starter: "Sunucumun diski doldu, yardım eder misin?"
opentag.audience: beginner
---
Pilot skill'leri disk-doldu, ad-parola ve rehberler linux-temel, windows-temel Faz 3'te (3.9).
MCP repo Faz 3
{"name": "proxmox", "transport": "stdio",
"command": ["uvx", "proxmox-mcp@1.2.0"],
"env": {"PROXMOX_TOKEN": "secret://site/proxmox-token"},
"runs_on": "site",
"tools": {"default": "write",
"overrides": {"get_vms": "read"}}}
- Şirket console'dan external MCP server ekler:
stdio(pinned versionuvx/npx) ya dahttp. - MCP server agent'ta çalışır:
runs_on: siteshared secret'larla,runs_on: pckişisel secret'larla. - opentagd hepsini kendi tek MCP endpoint'inin arkasında toplar (
mcp_<server>_<tool>); onay, audit ve masking her tool'da aynıdır. readOnlyHint'a güvenilmez: sınıf varsayılanwrite, console'da tek tekreadişaretlenir.
Ansible catalog'u Çalışıyor
Yalnız catalog.yml'deki playbook'lar çalışır; vars catalog tanımına göre doğrulanır. Akış: ansible_search → ansible_check (write playbook'u --check --diff) → onay → ansible_run → audit'i yeniden çalıştırıp karşılaştırma. macOS, Linux ve Linux server agent'ta sunulur.
| Playbook | Mod | Ne yapar |
|---|---|---|
cis_audit | read | CIS Ubuntu 24.04 compliance audit'i; başarısız kontrolleri raporlar, düzeltme yapmaz |
ssh_hardening | write | Root ve parola girişi kapalı, güçlü algoritmalar, deneme sınırı; anahtarla giriş açık kalır |
os_hardening | write | Kernel ayarları, parola kuralları, dosya izinleri, auditd |
firewall_ufw | write | Gelen trafik kapalı; SSH ve izin verilen portlar açık |
fail2ban | write | Deneme saldırısı yapan IP'leri geçici engeller |
package_update | write | Bekleyen paket güncellemelerini uygular |
12 · Katalog
Katalog: IT çalışanı ne yazacağını bilmeden işe başlar
Console'a Katalog sayfası gelir Faz 3. Her kart bir skill'dir: kart metni, kategori ve starter cümlesi skill'in metadata alanından gelir. Karta tıklamak sohbeti başlatır; iş yine sohbetin içinde, AI'ın skill'i izlemesiyle yürür. Ayrı bir form ya da template engine yoktur.
Katalog
Şirketinizin skill'lerinden hazır işler. Bir kart seçin, sohbet onunla başlar.
Linux
Diski dolan sunucuda yer açar: neyin yer kapladığını bulur, seçtiğiniz temizliği onayla yapar.
Chat'te başlat →Bekleyen güncellemeleri listeler, şirketin bakım kuralıyla package_update playbook'unu çalıştırır.
Windows / AD
Kullanıcıyı bulur, parolasını sıfırlar ya da hesap kilidini açar; değişiklik onay kartından geçer.
Chat'te başlat →Kubernetes
Event ve log'lardan nedeni bulur; gerekirse rollout restart ya da scale önerir.
Chat'te başlat →SMTP connection'ını test eder, onayla bir test e-postası gönderir.
Chat'te başlat →Network / VPN
Headscale'de kullanıcıya preauth key üretir, cihazın bağlandığını doğrular.
Chat'te başlat →Güvenlik / Uyum
CIS Ubuntu 24.04 audit'ini çalıştırır, başarısız kontrolleri özetler; hiçbir şeyi değiştirmez.
Chat'te başlat →Önce --check --diff ile neyin değişeceğini gösterir, onaydan sonra ssh_hardening'i uygular.
opentag.card'dan, kategori opentag.category'den, rozet opentag.audience'tan, gereken capability opentag.requires'tan, kaynak skill'in central ya da shared oluşundan gelir. shared kartlar şirketin kendi skill'leridir (örnek adlar). "Başlangıç" filtresi açılış ekranındaki kartlarla aynı veridir.disk-doldu skill'ini izliyorum. Hangi sunucu?
site-ofis/ssh/web-01)○ db-01○ Listede yokssh_read web-01 · df -h, du -xh /var | sort -h read · onaysız/ %97 dolu. En büyükleri: /var/log/journal 6,2 GB, eski .tar.gz yedekleri 3,1 GB. Ne yapalım?
- Tool
ssh_run·journalctl --vacuum-size=500M- Connection
site-ofis/ssh/web-01· server agent- Etki
- Eski journal kayıtları silinir, yaklaşık 5,7 GB açılır
- Geri alma
- Silinen log geri gelmez; servisler etkilenmez
- Doğrulama
- Ardından
df -h /
ssh_run job server agent'ta · ticket doğrulandı done · ardından ssh_read df -h / → %38Disk %38'e indi. Bu çözümü bu sunucu için bir shared skill olarak kaydetmemi ister misin?
Nasıl çalışır
- Kart listesi. Console
GET /v1/skillsile tenant'ın skill'lerini (central + shared)metadata'larıyla alır veopentag.category'ye göre gruplar. skill repo, sync metadata: Faz 3 (#30) - Chat'te başlat. Console sohbeti açar ve
opentag.startercümlesini ilk mesaj olarak yazar. Sohbet console relay ile PC'deki OpenCode'da çalışır. Faz 3 (#28, #29, #33, #34) - AI skill'i yükler. Skill bundle sync ile PC'de zaten vardır; OpenCode skill'i yükler ve adımlarını izler. Çalışıyor
- Seçenekli sorular. Sunucu, kapsam, yöntem gibi kararlar seçenekli sorularla alınır; kullanıcı komut yazmaz. soru tool'u console formu: Faz 3 (#33)
- Read tool'lar ve preview.
ssh_read,k8s_get,ansible_check(--check --diff) gibi read adımları onaysız çalışır; connection başka agent'taysa job olarak gider. Çalışıyor - Onay kartı. Write adımı planıyla (hedef, etki, geri alma, doğrulama) console'da onay kartı olur; onay yalnız Zitadel session'ıyla verilir. Faz 2 (#18, #25) Bugün aynı adım OpenCode'un permission prompt'una düşer.
- Job doğru agent'ta. Platform imzalı ticket'la job'ı connection'ın bulunduğu agent'a (çoğu zaman server agent) gönderir; agent ticket'ı ve local allowlist'i doğrular. job routing ticket: Faz 2 (#19, #20)
- Sonuç ve audit. AI sonucu read tool'la doğrular ve özetler; agent'ta
audit.logyazılır, platformda audit summary Faz 4'te. Çözüm yeni bir skill olarak kaydedilebilir, paylaşılınca kataloğa kart olarak girer. local audit audit summary: Faz 4 (#41)
Şirkete göre değişir
- Katalog tenant'ın skill'lerinden oluşur: herkese gelen
centralskill'ler ve şirketin kendisharedskill'leri. Şirket sistemlerine göre skill seti ayarlanır; ayrıca bir filtre mantığı yoktur. sharedskill'ikidemli_itvesirket_adminipaylaşır;itkullanıcısı kartları görür ve kullanır.opentag.requireskartın gerektirdiği capability'yi gösterir (ör.windows); connection yoksa AIrequest_connectionile form linki verir.
Bugün ne var, ne gelecek
- Çalışıyor skill repo, paylaşım ve sync, paketle gelen skill'ler (
kubernetes,mail,headscale,ansible…), Ansible catalog'u, job routing. - Faz 2 onay kartı, imzalı ticket, PowerShell tool'ları (
ad-parolaiçin). - Faz 3 skill
metadataAPI'si, Katalog ve başlangıç ekranı, console chat ve relay, pilot skill'lerdisk-dolduvead-parola(#36).
13 · Deploy ve operasyon
Deploy, CI, release ve geliştirme süreci
Çalışma ortamı
deploy/k8s/- k3s; Traefik ingress, cert-manager ile Let's Encrypt (DNS-01) sertifikaları.
- Namespace'ler:
opentag-backend(API, Postgres),opentag-landing(portal),opencode-web(chat UI ve indirmeler),opentag-presentation(bu site). - Image'lar local build edilir ve node'un containerd'sine import edilir; registry yok. Her bileşenin
deploy.sh'ı vardır. - Sunucu tarafı secret'lar k8s secret'larında üretilir ve korunur (
SIGNING_SEED, admin token); LiteLLM master key her deploy'da LiteLLM'in secret'ından kopyalanır.
CI
.github/workflows/ci.yml(push, pull request, elle): Go (platform ve agent)vet+ test, platform testleri gerçek Postgres servisiyle; agent için darwin/arm64, windows/amd64, linux/amd64 cross-compile; guard plugin testleri ve packager script'lerinin syntax kontrolü; portalnext build.security.yml: govulncheck,npm audit, OSV-Scanner.- Local'de aynı gate:
.agents/check.sh(test Postgres'ini kendisi başlatır).
Release ve paketler
release.yml · v* tag'i- OpenCode binary'leri, opentagd, Ansible paketi; ardından macOS DMG, Windows NSIS installer, Linux tar.gz (x64, arm64) ve GitHub release.
- macOS:
~/Library/Application Support/OpenTag, LaunchAgent. Windows:%LOCALAPPDATA%\OpenTag, oturum açılışında başlar. Linux: systemd--userservice. Hiçbiri admin yetkisi istemez. - Paketler imzasız (karar: code signing sertifikası şimdilik yok): macOS'ta ilk açılışta sağ tık → Aç, Windows'ta SmartScreen uyarısı. Linux paketi henüz gerçek bir masaüstünde denenmedi.
- Uninstaller'lar Keychain / Credential Manager kayıtlarını ve çalışma dizinini de siler.
Geliştirme süreci
issue → implement → review → deliver- Her task bir GitHub issue'dur; faz başına bir milestone. Her fazın kabul senaryosu vardır ve canlıda çalıştırılır.
- implement: kendi git worktree'si ve branch'inde; acceptance criteria numaralanır, önce file:line düzeyinde gap analysis, sonra testlerle yalnız delta; gate gerçekten çalıştırılır.
- review: yazanı görmemiş, farklı modelde yeni bir session; criteria'yı task'tan çıkarır, gate'i yeniden çalıştırır, en az bir guard'ı bilerek bozup testin yakaladığını gösterir. Kimse kendi işini kabul etmez.
- deliver: squash merge, ilgili bileşenlerin deploy'u, health check ve main'de CI takibi.
- Auth, migration, secret, prod ve major dependency değişiklikleri owner'ın açık onayını ister.
14 · Yol haritası
Dört faz; her faz bir kabul senaryosuyla biter
Skeleton
TamamlandıPC'deki AI, şirket sunucusundaki bir connection'da read job'ını platform üzerinden çalıştırır.
Onay ve secret
Planlı · 12 issueAD parola sıfırlama: secret console'dan girilir, job console'da onaylanır, server agent ticket ile çalıştırır.
Console ve repo'lar
Planlı · 11 issuePilot senaryosu baştan sona console'dan: Katalog kartı → sohbet → onay → sonuç; skill ve MCP repo, üyeler, limitler.
Hardening
Planlı · 12 issueScheduled job'lar, audit, eski kodun kaldırılması, disconnect ve recovery testleri, kurulum belgesi.
Faz kabul edilmeden sonraki faz deploy edilmez. Çalışan akışlar faz boyunca bozulmaz; eski yollar ancak Faz 4'te kaldırılır. Süreler plan tahminidir.
Faz 1 · Skeleton Tamamlandı
Canlı platformda kabul edildi; bağımsız review bir turda kurulum token'ının portal sayfasından denenmediğini bulup reddetti, sayfa üzerinden yapılan testten sonra kabul etti.
| Kabul adımı | Sonuç |
|---|---|
1. Ajanlar sayfasından kurulum token'ı, VM'de opentagd install --server, agent aynı sayfada online | Geçti (token sayfadaki formla üretildi, tekrar kullanım reddedildi, sayfadan revoke) |
2. Server agent'ta opentagd secret set ile ssh connection'ı | Geçti |
3. PC sohbetinde ssh_read df -h platform üzerinden server agent'ta | Geçti; connection discovery eksiği #65 ile kapatıldı |
| 4. Server agent restart olur, kendiliğinden reconnect olur, bekleyen job teslim edilir | Geçti (startup'tan 1 sn sonra; VM reboot'u da denendi) |
| 5. Başka tenant'ın kullanıcısı agent'ı, connection'ı, job'ı göremez | Geçti (boş listeler; job, cancel, delete, connection endpoint'lerinde 404) |
1.7 ansible_check gerçek bir VM'deki server agent'ta | Geçti |
Kapanan issue'lar: #11 CI'da platform Postgres testleri · #12 PC tool routing · #13 canlıda SQLite → Postgres, WSS ve queue · #14 test VM'leri · #15 Faz 1 kabulü · #51 skill sync testi · #56 backend'in superuser olmayan role ile bağlanması (RLS zorunlu) · #57 Go 1.27.3 toolchain · #58 kesin bekleme süresi ve doğrulanmış cancel · #63 release artefact saklama · #65 site agent connection'larının PC'de listelenmesi.
Faz 2 · Onay ve secret Planlı
Kabul senaryosu
- Admin console'dan Windows Server için shared
sshconnection'ı (shell: powershell) ekler; parola tarayıcıda şifrelenir, platform log'unda ve veritabanında açık değer yoktur. - AI AD kullanıcısını
powershell_readile bulur,powershell_runile parolasını sıfırlamak ister; console'da onay kartı çıkar. - Server agent ticket'ı doğrular ve çalıştırır; aynı ticket ikinci kez
ticket_invalid. - AI approval endpoint'ini çağıramaz: device token ve MCP key 401.
policy.yaml'dadeny_tools: ["powershell_run"]: platform onaylasa bile job reddedilir.- Agent makinesi silinip yeniden kurulur; şifreli backup ve recovery key ile secret'lar geri gelir.
| Issue | Bileşen | Task |
|---|---|---|
| #16 · 2.1 | agent | Tool sınıf/risk tablosu, MCP annotation'ları, hello'da |
| #17 · 2.2 | platform | Policy: default'lar, kurallar, en sıkı kazanır, capability-role eşlemesi |
| #18 · 2.3 | platform | Onaylar: yalnız Zitadel, ask/approval, self-approval engeli, timeout |
| #19 · 2.4 | platform | Ticket imzalama: Ed25519, JWS, JCS, ortak test vector'leri |
| #20 · 2.5 | agent | Ticket doğrulama, jti kaydı, policy.yaml; PC ve server agent'ta |
| #21 · 2.6 | agent | age secret store, recovery key, backup/restore, secret.put |
| #23 · 2.7 | agent | powershell_read / powershell_run |
| #24 · 2.8 | platform | Shared connection ve secret endpoint'leri, grants |
| #25 · 2.9 | portal | Onay kartı, onay bekleyenler, tarayıcıda age-encryption |
| #26 · 2.10 | client | opentag tool'larında OpenCode permission'ı allow, "onay bekleniyor" prompt'u |
| #22 · 2.11 | deploy | Windows Server 2025 test VM'i (AD DS, OpenSSH) |
| #27 · 2.12 | kabul | Kabul senaryosu ve onay bypass denemeleri |
Faz 3 · Console ve repo'lar Planlı
Kabul senaryosu
- Davetle gelen
itkullanıcısı console'da skill kartlarını (Katalog) görür, "Disk doldu" kartında "Chat'te başlat"a tıklar. - Sohbet relay üzerinden açılır, tarayıcı
127.0.0.1'e hiç istek atmaz; AI skill'i izler, seçenekli sorular sorar, temizlik onaydan sonra yapılır. - Admin server agent'a örnek bir MCP server ekler; write tool onaydan geçer.
- LLM bütçesi dolunca kullanıcı anlaşılır bir hata görür; admin usage'ı console'da görür.
- Admin kullanıcıyı disable eder; cihazı ve LLM key'i hemen çalışmaz olur.
| Issue | Bileşen | Task |
|---|---|---|
| #28 · 3.1 | platform | Relay: /v1/relay/{agent_id}/*, SSE, path allowlist, yalnız owner |
| #29 · 3.2 | agent | Relay endpoint'leri: relay.open → local OpenCode ve /opentag/* |
| #33 · 3.3 | portal | Console chat: useChat, relay transport'u, seçenekli soru formları |
| #34 · 3.4 | portal | Starter ve Katalog, skill'ler, MCP, agent'lar, üyeler, policy, usage sayfaları |
| #30 · 3.5 | platform | Skill metadata, paylaşım role'leri, MCP repo, config.changed |
| #35 · 3.6 | agent | MCP aggregator: external server'ları çalıştırma ve tek endpoint'ten sunma |
| #31 · 3.7 | platform | Üyeler, davet, disable, tenant açma script'i |
| #32 · 3.8 | platform | LiteLLM limitleri: team, bütçe, TPM/RPM, /v1/usage |
| #36 · 3.9 | ansible | Rehber ve pilot skill'leri (disk-doldu, ad-parola) |
| #37 · 3.10 | client | OpenCode config düzeltmeleri, role policy'sine göre bash |
| #38 · 3.11 | kabul | Kabul senaryosu |
Faz 4 · Hardening Planlı
Kabul senaryosu
- AI gece disk temizliğini schedule etmeyi önerir; standing approval; job gece server agent'ta çalışır, sonuç console'da; argüman değişirse onay düşer.
- Admin audit sayfasında kimin, hangi tool ile, hangi connection'da, hangi kararla ne yaptığını görür; komut çıktısı yoktur.
- Google, n8n ve merkezi entegrasyonlardan portalda ve API'de iz kalmaz.
- Disconnect ve recovery testleri yeşil.
- Pilot kurulum belgesi hazır.
| Issue | Bileşen | Task |
|---|---|---|
| #39 · 4.1 | platform | Scheduled job'lar ve standing approval |
| #40 · 4.1a | agent | schedule_create MCP tool'u |
| #43 · 4.2 | portal | Scheduled job'lar ve audit sayfaları |
| #41 · 4.3 | platform | Audit summary, GET /v1/audit |
| #42 · 4.3a | agent | audit.batch |
| #44 · 4.4 | platform | Google, n8n ve merkezi entegrasyonların kaldırılması |
| #45 · 4.5 | agent | Entegrasyon tool'ları ve tarayıcı → localhost yolunun kaldırılması |
| #46 · 4.5a | client | client/ altındaki referansların temizlenmesi |
| #47 · 4.6 | portal | Entegrasyon ve Google sayfalarının kaldırılması |
| #48 · 4.7 | deploy | n8n'in kaldırılması, Postgres backup'ından restore denemesi |
| #49 · 4.8 | kabul | Failure testleri |
| #50 · 4.9 | kabul | Pilot kurulum belgesi ve release notları |
Pilot örnekleri (core'u doğrulamak için)
| Ortam | Örnek |
|---|---|
| PC agent | Kişisel SSH connection'ıyla disk-doldu: teşhis, seçenekli temizlik, onay, doğrulama |
| Server agent | Shared Windows Server connection'ıyla ad-parola: parola sıfırlama, hesap kilidi açma |
| Scheduled | Server agent'ta her gece disk temizliği, standing approval ile |
| MCP | Server agent'ta örnek bir external MCP server; tool'u onaydan geçerek çalışır |
15 · Kararlar
Tasarım kararları ve gerekçeleri
Kaynak: docs/kararlar.md. Platform yeri ve şirket sınırı kararları iki ayrı modelin bağımsız danışmasıyla, sekiz maddede mutabakatla verildi (14 Ekim).
| Konu | Karar | Gerekçe |
|---|---|---|
| Platform yeri | MVP'de bizim sunucumuzda, multi-tenant | Tek yönetim noktası, hızlı teslim. Kod single-tenant kurulumu engellemez; müşteride kurulum ileride aynı image ile |
| Shared secret'lar | Şirketin server agent'ında, şifreli dosyada; OpenBao yok | Secret şirketten çıkmaz, platform yalnız adını bilir; ek bir vault servisi işletmek gerekmez |
| Şirkette kalan veri | Sohbet ve ham çıktılar agent tarafında | Platformda yalnız kullanıcı, catalog, job durumu, onay ve audit summary |
| İletişim | Agent'tan outbound tek WSS/443; queue Postgres'te | Şirkette port ve VPN gerekmez; job kaybolmaz (lease, ACK, redelivery) |
| Console → PC | Platform relay | Tarayıcıdan localhost erişimi kalkar |
| Onay | Ed25519 imzalı tek kullanımlık approval ticket + agent'ta local allowlist | AI kendi job'ını onaylayamaz; platform ele geçirilse bile local allowlist geçerli |
| Generic core | Ürüne özel kod yok; entegrasyonlar skill ya da MCP | Yeni sistem çoğu zaman bir skill'dir. Pack/Runbook YAML'ı ve template engine (DBOS) bu yüzden kaldırıldı; scheduled job = tek tool çağrısı |
| Veritabanı | Postgres (SQLite'tan geçiş), goose | Multi-tenancy için RLS, queue için row lock (SKIP LOCKED), backup |
| Runtime | OpenCode fork'u kalır | Agent Skills biçimini doğrudan okur; MCP, permission ve SSE API'si olan açık kaynak (MIT) bir runtime ve web UI |
| UI | Kendi console'umuz: mevcut portal + shadcn, AI SDK, AI Elements | En az uğraş, güncel kütüphaneler; chat, tool call, onay, form ve streaming desteği |
| Model provider | Şimdilik DeepSeek, LiteLLM arkasında | Provider değiştirilebilir. Veri koruması ayrı llm-gateway projesinde (Presidio ile masking ve pseudonymization) |
| Standing approval | Düşük riskli scheduled job'lar için | Her gece aynı job için onay istemek kullanılamaz bir akış olurdu; sınır risk ≤ medium, 90 gün |
| Sunucuda root | Root'un secret store'a erişebilmesi kabul | Store otomatik açılır; gereksiz karmaşıklık yok |
| Sunucusuz şirket | Yalnız PC agent ve sunucu gerektirmeyen işlevler | Scheduled job ve shared connection server agent ister (requires_server) |
| Code signing | Şimdilik yok | Önce secret yönetimi; code signing ve auto-update MVP dışı |
| Google ve n8n | Bırakıldı, Faz 4'te kaldırılır | Generic core kararıyla çelişir |
16 · Teknik SSS
Sık sorulan teknik sorular
Neden platform bizim sunucumuzda, şirketin içinde değil?
MVP'de tek yönetim noktası ve hızlı teslim için. Şirketin yetkisi ve verisi şirkette kalır: secret'lar ve ham çıktılar agent'larda, platform müşteri sistemine kendisi dokunmaz. Kod single-tenant kurulumu engellemez (aynı image, env ile config, her tabloda tenant_id); müşteri sunucusuna kurulum MVP sonrasıdır.
Multi-tenancy nasıl sağlanıyor? Bir tenant başkasının verisini görebilir mi?
Tenant Zitadel org id'sidir ve token'dan gelir. Postgres'te her tabloda tenant_id ve zorunlu RLS var; backend RLS'i atlayamayan opentag_app role'üyle bağlanır, her DB connection'ında app.tenant_id set edilir. Faz 1 kabulünde ikinci tenant'ın kullanıcısı için listeler boş, job ve connection endpoint'leri 404 döndü.
Veriler nerede durur? Sohbetler platforma gelir mi?
Sohbet geçmişi, ham komut çıktıları ve secret'lar agent'larda kalır. Platformda kullanıcı, role, agent, skill, job durumu ve platform üzerinden route edilen job'ın argümanı ile maskelenmiş sonucu durur. LLM'e giden içerik LiteLLM üzerinden model provider'a gider; platform bu içeriği saklamaz ve log'a yazmaz. Kişisel veri maskeleme ayrı llm-gateway projesinde yürür.
Parolalar ve token'lar AI'a gider mi?
Hayır. Değerler portal formuyla girilir, model yalnız secret:// referansı görür, referans opentagd içinde çözülür. Tool çıktıları ve hata mesajlarında bütün connection'ların secret'ları *** olur (düz, JSON, URL-kaçışlı, base64, hex biçimleri). Guard plugin düz secret pattern'i içeren argümanları engeller; argümanda local secret değeri olan job platforma hiç gitmez (secret_in_args). Masking bir security boundary değildir: bir script değeri parçalayıp yazarsa yakalanmaz; bu yüzden script çalıştıran tool write sınıfında ve onaylıdır.
AI kendi job'ını onaylayabilir mi?
Bugün write tool'lar OpenCode'un permission prompt'unda kullanıcı onayına düşer. Faz 2'de approval endpoint'i yalnız Zitadel kullanıcı session'ıyla çağrılır; device token ve MCP key 401 alır. Agent write job'ı ancak tool'a, connection'a ve argüman hash'ine bağlı, imzalı ve tek kullanımlık bir approval ticket ile çalıştırır. Bu, Faz 2 kabul senaryosunun 4. adımıdır.
Platform ele geçirilirse şirkette ne olur?
Bugün (Faz 1) platform policy'si her job'a allow der ve ticket yoktur; bu fazın açık bir sınırıdır. Faz 2'de iki katman gelir: imzalı ticket ve agent'ın local allowlist'i (policy.yaml, sunucuda root'a ait ve 0600). Platform bu dosyayı değiştiremez; örneğin deny_tools: ["powershell_run"] platform onaylasa bile job'ı durdurur. Secret değerleri platformda hiç bulunmaz.
Agent offline ise ya da connection koparsa ne olur?
Agent 25 sn'de bir ping atar; 60 sn sessizlikte offline sayılır ve 1-60 sn arası jitter'lı backoff ile reconnect olur. Agent son 2 dk içinde görülmediyse yeni job 409 agent_offline alır; reconnect ediyor sayılırsa job queue'da bekler. Queue'da 10 dk içinde başlamayan job failed (deadline_exceeded) olur. Faz 1 kabulünde restart edilen agent startup'tan 1 sn sonra bağlanıp bekleyen job'ı aldı.
Bir job iki kez çalışabilir mi?
Read job güvenle redeliver edilir. Agent ack göndermeden koparsa ya da lease dolarsa job attempt+1 ile redeliver edilir. ack'ten sonra kopan write job unknown olur ve kendiliğinden tekrarlanmaz. Agent biten job'ların sonucunu saklar; aynı job_id tekrar gelirse tool'u yeniden çalıştırmadan saklanan sonucu gönderir. Yarıda kesilen çağrının cancel'ı doğrulanamazsa AI'a durumu önce read tool ile kontrol etmesi söylenir.
Nasıl ölçeklenir?
Bugün platform tek replica çalışır. Job durumu Postgres'tedir ve dispatch FOR UPDATE SKIP LOCKED ile yapılır; agent başına aynı anda en çok 8 job çalışır. Agent'ların WSS connection'ları ve long-poll istekleri process belleğindedir; birden fazla replica'ya geçmek için connection'ın hangi replica'da olduğunu bilen bir routing gerekir. MVP'de buna yönelik bir task yok. Ağır iş (tool çalıştırma) zaten agent'larda, yani şirket tarafında dağıtıktır.
Hangi model kullanılıyor, maliyet nasıl kontrol ediliyor?
Bugün DeepSeek: ana agent deepseek-flash-deepseek, uzman subagent deepseek-pro-deepseek. Model erişimi LiteLLM arkasındadır, sağlayıcı değiştirilebilir. Her kullanıcının kendi LiteLLM key'i vardır ve harcaması /v1/me/usage ile görülür. Faz 3'te şirket başına bütçe, TPM/RPM, izinli modeller ve kullanıcı bütçesi gelir; limit aşımında 429 llm_limit_exceeded. LiteLLM'in sessizce başka modele fallback yapması Faz 3'te düzeltilecek bilinen bir ayar sorunudur.
Neden OpenCode?
Açık kaynak (MIT), tool calling, MCP, permission'lar, subagent ve event stream (SSE) API'si olan hazır bir agent runtime'ı ve web UI'ı. Agent Skills biçimini doğrudan okur, bu yüzden skill repo ek dönüşüm istemez. Fork'ta marka, sabit backend adresi, harici skill dizinlerinin kapatılması, terminalin ve upstream'e giden connection'ların kaldırılması gibi değişiklikler var; yerleşik build/plan agent'ları kapalı.
Neden Postgres, neden Go?
Postgres: multi-tenancy'yi veritabanı düzeyinde zorlayan RLS, queue için row lock'lar, olgun backup. SQLite'tan bu yüzden geçildi. Go: agent tek statik binary olarak macOS, Windows ve Linux'a cross-compile edilir (CI her push'ta üçünü build eder); platform stdlib net/http ile tek servistir.
Windows desteği ne durumda?
PC uygulaması Windows x64 için NSIS installer ile gelir, kullanıcı hesabı altında çalışır, secret'lar Credential Manager'dadır. Server agent Windows'ta service olarak kurulur; Windows server agent'ta Ansible tool'ları yoktur (Ansible Windows'ta control node olamaz). Windows sunucuları yönetmek için powershell_read / powershell_run (Windows'un OpenSSH'ı üzerinden) Faz 2'de gelir ve Windows Server 2025 test VM'inde AD komutlarıyla doğrulanır.
Şirkette port açmak, VPN kurmak gerekir mi?
Hayır. Her agent platforma outbound tek bir WSS connection (443) açar. Server agent hiç local port açmaz; PC agent yalnız 127.0.0.1'de dinler.
Listede olmayan bir sistem nasıl desteklenir?
Çoğu zaman yalnız bir skill yazılır: sistemin http_api, ssh ya da postgres gibi generic bir connection type ile nasıl yönetileceği anlatılır. Yetmezse AI yeni bir connection type tanımlar (define_connection_type); kullanıcı onaylamadan kullanılamaz. Faz 3'te şirket, vendor'ın MCP server'ını MCP repo'ya ekleyebilir; tool'ları aynı onay ve audit'ten geçer.
Çalışan şirketten ayrılınca erişimi nasıl kesilir?
Bugün portaldan cihaz revoke edilir: sonraki istekler 401 device_revoked alır, agent token'ı siler ve bütün endpoint'leri kapatır. Server agent portalın Ajanlar sayfasından revoke edilir ve açık WSS connection'ı kapanır. Faz 3'te kullanıcıyı disable etmek cihazlarını ve LiteLLM key'ini birlikte revoke eder.
Kim ne yaptı, audit nasıl tutulur?
Bugün her agent her MCP çağrısını kendi audit.log'una yazar (zaman, tool, connection, maskeli parametreler, sonuç); platform job'larının durumu jobs tablosundadır. Faz 4'te platformda audit summary gelir: kim, hangi tool, hangi connection, hangi karar, kim onayladı, sonuç ve çıktının sha256'sı. Komut çıktısı ve sohbet platforma gönderilmez.
Tehlikeli komutlar nasıl engelleniyor?
Üç katman var. Guard plugin bash komutlarını parçalarına ayırıp rm -rf, sudo, indirip çalıştırma gibi pattern'leri engeller. ssh_read yalnız allowlist'teki read-only komutları kabul eder. Değişiklik yapan her tool plan ister ve onaya düşer. Guard ve ssh_read filtredir; security boundary Faz 2'de ticket ve local allowlist'tir.
Sunucusu olmayan küçük bir şirket kullanabilir mi?
Evet, yalnız PC agent ile: kişisel connection'lar ve şirket ağı gerektirmeyen işler. Shared connection'lar, scheduled job'lar ve runs_on: site MCP server'ları server agent ister; yoksa requires_server döner.
Backup ve felaket durumunda ne olur?
Platform Postgres'i her gece backup'lanır; backup'tan restore denemesi Faz 4'te (4.7). Server agent'ın secret store'u için Faz 2'de kurulumda bir kez gösterilen recovery key ve opentagd secret backup / restore gelir; makine silinip yeniden kurulunca secret'ların geri gelmesi Faz 2 kabulünün 6. adımıdır.
Uygulama imzalı mı, auto-update var mı?
Hayır, bilinçli bir karar. macOS paketi ad-hoc imzalıdır (ilk açılışta sağ tık → Aç), Windows installer'ı SmartScreen uyarısı verir. Developer ID ve Windows code signing sertifikası ile auto-update MVP dışında.
Kalite nasıl güvence altında?
CI her push ve pull request'te Go testlerini gerçek Postgres'le, agent'ın üç platform için build'ini, guard testlerini ve portal build'ini çalıştırır; ayrıca govulncheck, npm audit ve OSV-Scanner. Her task bağımsız bir review session'ından geçer. Her fazın kabul senaryosu canlıda çalıştırılır. Faz 4'te disconnect, restart, ticket replay ve recovery için failure testleri var.
17 · Linkler ve sözlük
Canlı adresler ve terimler
| Adres | Ne |
|---|---|
| opentag.nesiler.com | Portal: login, indirme, enrollment, agent'lar, connection'lar, skill'ler |
| api.opentag.nesiler.com/healthz | Platform health check ({"ok":true}) |
| api.opentag.nesiler.com/.well-known/jwks.json | Local access token'ı imzalayan Ed25519 public key |
| chat.opentag.nesiler.com | Chat UI (OpenCode fork, statik) |
wss://api.opentag.nesiler.com/v1/agent/connect | Agent connection'ı (device token gerekir) |
Repodaki kaynaklar
docs/mvp-mimari.md mimari · docs/islevler.md işlevler · docs/api.md arayüzler (§7 MVP contract'ı) · docs/fazlar/ fazlar ve kabul senaryoları · docs/kararlar.md kararlar.
Sözlük
| Tenant | Bir müşteri şirket; Zitadel org'u. Bütün veriler tenant'a bağlıdır. |
|---|---|
| Agent | opentagd. pc (PC agent): IT çalışanının bilgisayarı, kullanıcıya bağlı. site (server agent): şirket sunucusu, şirkete bağlı. |
| Connection | Bir sisteme erişim tanımı (ssh/web-01); secret'ları agent'ta durur. ID'si <agent_id>/<type>/<name>. |
| Capability | opentagd'nin generic tool grubu: linux, windows, kubernetes, database, http, script, mail. |
| Skill | Agent Skills biçiminde bilgi ve yöntem: SKILL.md, references/, scripts/. |
| MCP | Model Context Protocol. opentagd tek MCP endpoint'idir; external MCP server'lar onun arkasında toplanır. |
| Job | Platform queue'sundaki tek bir tool çağrısı; lease, ACK ve redelivery ile agent'a gider. |
| Approval ticket | Onaylanmış write job için platformun imzaladığı, 10 dk'lık, tek kullanımlık JWS (Faz 2). |
| Standing approval | Scheduled job için tool, connection ve argüman hash'ine bağlı, en çok 90 günlük onay (Faz 4). |