Developers

개발자는 Schift를 메모리 API처럼 씁니다.

웹 UI는 사용자가 보는 표면입니다. 개발자 표면은 소스 연결, 검색, 채팅, 업무 후보, 승인 로그를 제품 밖의 에이전트와 CLI, MCP, 사내 서비스가 같은 계약으로 호출하게 만드는 표면입니다.

memory.search.ts
const result = await schift.memory.search({
  query: "회의록 12차 기준 생산 기준이 바뀐 품목만 알려줘",
  topK: 8,
  hybrid: {
    vector: true,
    bm25: true,
    metadata: true,
    graph: false,
  },
  prefilter: {
    orgId: "org_821",
    workspaceId: "ops",
    tombstone: false,
    revision: "latest",
    effectiveAtLte: "now",
    aclFor: "user_123",
  },
  rerank: "schift-rerank-1",
});

Source API

Gmail, Slack, Drive, Notion, S3, GCS, ERP/MES export, POS, Excel, 음성 메모를 같은 ingest 계약으로 받습니다.

Memory Query API

Vector, BM25, metadata prefilter, revision, tombstone, timestamp, auth 범위를 한 요청에서 명시합니다.

Workflow Hooks

답변 이후에 생산 기록, 로스 차감, 청구 확인, 담당자 이관 같은 업무 후보를 생성하고 승인 로그로 닫습니다.

MCP / SDK

사내 에이전트, CLI, MCP 서버, 웹 UI가 같은 메모리 계약을 쓰도록 TypeScript/Python SDK와 MCP 표면을 분리합니다.

Operations contract

실제 운영 API에는 검색 말고도 여러 계약이 필요합니다.

Schift의 Common API는 답변 endpoint 하나가 아닙니다. 연결, 권한, 사용량, 동기화, 감사, 버전 정책이 같은 요청 경계 안에서 움직여야 웹, worker, engine, MCP가 서로 어긋나지 않습니다.

Idempotency-Key orgId / workspaceId sourceId / externalId aclFor / role scope revision policy tombstone policy usage limit check audit event id

Auth / Tenant

조직, 워크스페이스, 사용자, 역할, 소스별 ACL을 검색 전 계약에 넣습니다. 웹 세션과 SDK 토큰은 같은 권한 해석을 공유합니다.

Billing / Usage

embedding, rerank, ingest, sync, search, workflow execution을 usage axis로 분리하고 trial gate와 hard limit을 API 앞에서 확인합니다.

Source Sync

OAuth, 파일 업로드, export poll, webhook, object-storage batch를 같은 sync job 상태와 idempotency key로 추적합니다.

Evidence / Audit

답변, 근거, 담당자 승인, 외부 시스템 반영 요청을 하나의 audit trail로 묶어 나중에 왜 그렇게 처리했는지 복원합니다.

Revision / Tombstone

최신본, supersedes, tombstone, effectiveAt, retention을 색인 전에 반영해 오래된 문서가 최신 답변을 오염시키지 않게 합니다.

Errors / Webhooks

rate limit, permission denied, stale source, schema mismatch, sync failed를 명시적 에러 코드와 webhook event로 노출합니다.

Contract

“최근 회의록”은 최신 revision만 보게 만들어야 합니다.

Schift API는 검색 전에 조직, 권한, tombstone, revision, timestamp, metadata를 먼저 줄입니다. 그 다음 hybrid search와 rerank가 들어가야 “회의록 12차”를 물었을 때 11차 내용을 거의 무시할 수 있습니다.

0. 소스 연결

await schift.sources.connect({
  provider: "slack",
  auth: { type: "oauth" },
  scopes: ["channels:history", "users:read"],
  sync: {
    mode: "incremental",
    cursor: "provider",
    schedule: "*/15 * * * *",
  },
  validation: {
    requireBusinessFormMatch: true,
    requireOwnerApproval: true,
  },
});

1. 소스 입력

await schift.sources.upsert({
  source: "gdrive",
  documentId: "meeting-12",
  title: "생산회의 12차",
  body,
  metadata: {
    orgId: "org_821",
    workspaceId: "ops",
    revision: 12,
    supersedes: ["meeting-11"],
    tombstone: false,
    effectiveAt: "2026-05-23T09:00:00+09:00",
    labels: ["MES", "production", "approved"],
  },
  acl: ["role:ops-manager", "team:production"],
});

2. 사용량 gate

const gate = await schift.usage.check({
  orgId: "org_821",
  axis: "embedding_tokens",
  model: "schift-embed-1-small",
  estimatedUnits: 18000,
});

if (!gate.allowed) {
  throw new SchiftUsageLimitError(gate.reason);
}

3. 업무 후보 생성

await schift.workflows.createCandidate({
  kind: "production_record",
  evidenceIds: result.evidence.map((item) => item.id),
  requiresApproval: true,
  assignee: "role:ops-manager",
  target: {
    system: "mes",
    ledger: "daily-production",
  },
});

4. 감사 이벤트

await schift.audit.events.create({
  kind: "workflow.approved",
  actor: "user_123",
  evidenceIds: result.evidence.map((item) => item.id),
  decision: {
    action: "post_to_mes_review_queue",
    reason: "meeting-12 supersedes meeting-11",
  },
});

Boundary

Web API와 Common API를 분리합니다.

Web API

로그인, 세션, 조직, 결제, 14일 trial gate, 온보딩, 소스 연결 UI, 사용량 화면처럼 웹 제품의 상태를 담당합니다.

Common API

SDK, MCP, CLI, worker, engine, 외부 서비스가 쓰는 ingest/search/chat/workflow 계약을 담당합니다.