{"_id":"@agentic-research/observer-core","name":"@agentic-research/observer-core","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@agentic-research/observer-core","version":"0.1.0","type":"module","description":"Portable provider-observer contracts with validated facts and explicit cursor handoff.","license":"Apache-2.0","keywords":["agentic-research","observer","event-stream","capnp"],"repository":{"type":"git","url":"git+https://github.com/agentic-research/canonical-hours.git","directory":"packages/observer"},"homepage":"https://github.com/agentic-research/canonical-hours/tree/main/packages/observer","bugs":{"url":"https://github.com/agentic-research/canonical-hours/issues"},"sideEffects":false,"main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org"},"dependencies":{"zod":"^4.4.3"},"devDependencies":{"@cloudflare/vitest-pool-workers":"0.18.7","@cloudflare/workers-types":"^5.20260722.1","wrangler":"^4.113.0","vitest":"4.1.10"},"scripts":{"build":"tsc -p tsconfig.build.json","test":"vitest run test","test:package":"pnpm run build && node -e \"import('./dist/index.js').then(() => console.log('package import ok'))\"","test:workerd":"vitest run --config vitest.workerd.config.mts"},"_id":"@agentic-research/observer-core@0.1.0","_integrity":"sha512-eL+bT4CToMm4aAJ8Q/FyDYd/jIkpKN/F2p+nZ9/1qz2bh5Ma7f1Ce8GHf42Tl96Dp7gvISvx7HkpTD1Zr5ot7Q==","_resolved":"/private/var/folders/h3/m8zflqfn203fxwfvhwqbt_c40000gn/T/07d46e27596a843bee1a8da58920f711/agentic-research-observer-core-0.1.0.tgz","_from":"file:agentic-research-observer-core-0.1.0.tgz","_nodeVersion":"25.9.0","_npmVersion":"11.12.1","dist":{"integrity":"sha512-eL+bT4CToMm4aAJ8Q/FyDYd/jIkpKN/F2p+nZ9/1qz2bh5Ma7f1Ce8GHf42Tl96Dp7gvISvx7HkpTD1Zr5ot7Q==","shasum":"d9e2bafad0cc54f1530df94b91073f5e792ae7be","tarball":"https://registry.npmjs.org/@agentic-research/observer-core/-/observer-core-0.1.0.tgz","fileCount":6,"unpackedSize":21969,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCF88uZAtOk8wjHg3n+2GpEyufpn0wbTZiip4QuXuy0lQIhAKeBPjGYUz38jIHU1MxedRC0DTyq+lKMzIl6nOl4fDQu"}]},"_npmUser":{"name":"jamestexas","email":"jamestexasgardner@gmail.com"},"directories":{},"maintainers":[{"name":"jamestexas","email":"jamestexasgardner@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/observer-core_0.1.0_1784934621167_0.3529999267439954"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-24T23:10:21.016Z","0.1.0":"2026-07-24T23:10:21.304Z","modified":"2026-07-24T23:10:21.545Z"},"maintainers":[{"name":"jamestexas","email":"jamestexasgardner@gmail.com"}],"description":"Portable provider-observer contracts with validated facts and explicit cursor handoff.","homepage":"https://github.com/agentic-research/canonical-hours/tree/main/packages/observer","keywords":["agentic-research","observer","event-stream","capnp"],"repository":{"type":"git","url":"git+https://github.com/agentic-research/canonical-hours.git","directory":"packages/observer"},"bugs":{"url":"https://github.com/agentic-research/canonical-hours/issues"},"license":"Apache-2.0","readme":"# `@agentic-research/observer-core`\n\nPortable, host-neutral contracts for turning provider records into validated\nobservation drafts.\n\nAn observer owns provider-facing work such as pagination, rate-limit handling,\nresponse validation, and normalization. It returns facts plus its proposed next\ncursor. The host owns credentials, persistence, cursor commits, scheduling,\ndelivery, and downstream projections.\n\nThat separation lets the same observer run directly in Canonical Hours today,\ninside a Cloister workerd bundle later, or behind another host without changing\nits provider logic.\n\n## Install\n\n```sh\npnpm add @agentic-research/observer-core\n```\n\nWithin this repository, pnpm resolves the package from\n`packages/observer` through the workspace protocol.\n\n## Define an observer\n\n```ts\nimport { z } from \"zod\";\nimport {\n  ObservationPipeline,\n  type Extractor,\n  type Transformer,\n} from \"@agentic-research/observer-core\";\n\ninterface Config {\n  repo: string;\n}\n\ninterface ReviewRecord {\n  id: string;\n  createdAtMs: number;\n  state: unknown;\n}\n\nconst extractor: Extractor<Config, ReviewRecord> = {\n  name: \"github\",\n  async extract({ config, cursor, signal }) {\n    const page = await fetchReviews(config.repo, { cursor, signal });\n    return {\n      records: page.reviews,\n      nextCursor: page.nextCursor,\n    };\n  },\n};\n\nconst transformer: Transformer<ReviewRecord, {\n  state: \"approved\" | \"changes_requested\";\n}> = {\n  payloadSchema: z.object({\n    state: z.enum([\"approved\", \"changes_requested\"]),\n  }),\n  transform(review) {\n    return {\n      subject: \"pr:agentic-research/canonical-hours#186\",\n      kind: \"github.pull_request.review\",\n      eventTimeMs: review.createdAtMs,\n      providerEventId: review.id,\n      payload: { state: review.state },\n    };\n  },\n};\n\nconst observer = new ObservationPipeline(extractor, transformer);\nconst batch = await observer.observe({\n  config: { repo: \"agentic-research/canonical-hours\" },\n  cursor: \"page:1\",\n});\n```\n\n`batch.observations` contains schema-validated drafts.\n`batch.nextCursor` is only a proposal: the host must not commit it until the\ncorresponding observations are durable.\n\nReturning `null` from `transform()` intentionally filters a provider record.\nMalformed observation metadata or payloads throw `ObservationValidationError`;\nthey are never logged-and-discarded silently.\n\n## Observation identity and provenance\n\nEvery draft carries:\n\n| Field | Meaning |\n| --- | --- |\n| `subject` | Canonical identity of the observed resource |\n| `kind` | Versionable fact vocabulary, such as `github.pull_request.review` |\n| `eventTimeMs` | Provider event time as a safe integer in Unix milliseconds |\n| `providerEventId` | Stable provider-side event identity used for deduplication and provenance |\n| `payload` | Provider-independent fact payload validated by the transformer schema |\n\nThe receiving host may add tenant, route, observer version, receipt,\nauthentication, and content-hash fields when it accepts the draft. Those fields\ndo not belong to the provider package.\n\n## Vespers and Cloister\n\nThe dependency direction is:\n\n```text\nGitHub / Linear observer package\n              ↓\n         observer-core\n          ↙          ↘\nCanonical Hours      Cloister runtime\nor Vespers adapter   and delivery\n```\n\nVespers projects drafts into its own lifecycle `Observation` vocabulary; it\ndoes not redefine the provider protocol. Cloister can consume this package from\nthe pnpm workspace now and can become the source repository later without\nchanging the npm package name or reversing the dependency direction.\n\n## Cap'n Proto schema\n\n`src/observation.capnp` ships with the npm package as the cross-runtime type\ndescription for `ObservationDraft` and `ObservationBatch`. TypeScript callers\nuse the interfaces exported from this package; future Rust or Go consumers can\ngenerate native types from the same schema.\n\n## Verification\n\nFrom the repository root:\n\n```sh\ntask observer:check\n```\n\nThis runs TypeScript compilation, unit tests, a published-entrypoint smoke test,\nand a live Miniflare/workerd portability test. Release and CI workflows call\nthe same Taskfile surfaces. The package owns those tasks in this directory's\n`Taskfile.yml`; the repository root imports it under the `observer:` namespace.\n","readmeFilename":"README.md","_rev":"1-ae143a1d366eaede4043f7fc18fc4d48"}