Scala 3 reimagining of Graphiti's core ideas (bi-temporal edges, episodic
ingestion, hybrid retrieval, contradiction-driven invalidation) on the
Typelevel stack, wired into ADK4S as durable agent memory. See
docs/graphstore-project.md for the full specification.
- Scala 3.8.4, sbt 1.12.12, Java 26.
sbt projects— list GraphStore's 10 modules + ADK4S's modules (via ProjectRef).sbt compile— compiles all 10 GraphStore modules (and the ADK4S modules they depend on).sbt Test/compile— compile main + test sources (munit, munit-cats-effect, Hedgehog are shared test deps across all modules).sbt scalafmtAll— format.sbt "scalafix --check"— lint (DisableSyntax + RemoveUnused + OrganizeImports + custom regex rules; scoped guards forbid infra imports indomain/core).sbt stryker4s— mutation testing (Ring 5; retargetstryker4s.confmutatelist per spec). Run withJAVA_OPTS="-Xmx4g -XX:+UseG1GC" sbt "api/stryker"(target specific module; rootstrykerruns all modules and OOMs). In multi-module builds, Stryker4s may report manyNoCoveragemutants because the test runner can't trace coverage through smithy4s HTTP indirection — the meaningful metric is "100% on covered code".- WartRemover is active (
Warts.unsafeminusTripleQuestionMark,Any,DefaultArguments).-Werroris on — use@nowarnwith a justification for unavoidable deprecations.
openspec/config.yamlis configured for theverified-scala3schema (v2).- The context section describes GraphStore's actual stack (10 modules, Ciris not PureConfig, munit+Hedgehog not ScalaTest/ScalaCheck, neotypes+Lucene+http4s+smithy4s, otel4s, ADK4S via ProjectRef).
- The concept-scanner lives at
openspec/schemas/verified-scala3/scanner/(scala-cli based; build artifacts are gitignored). - Skills for the OpenSpec workflow are available:
openspec-new-change,openspec-continue-change,openspec-apply-change,openspec-verify-change,openspec-archive-change, etc.
GraphStore consumes ADK4S via ProjectRef against the local source checkout at
/home/gruggiero/git/rs/adk4s (configured as adk4sBase in build.sbt). This
gives live co-development: edits in ADK4S are visible immediately, no
publishLocal needed.
Requirements / constraints:
- sbt version must match ADK4S (1.12.12) —
ProjectRefloads ADK4S'sproject/(plugins), so version mismatches break the build. - Scala version must match ADK4S (3.8.4) — TASTy is backward-compatible only (newer compiler reads older TASTy); 3.4.2 cannot consume 3.8.4 TASTy.
- sbt-wartremover is in GraphStore's
project/plugins.sbt— ADK4S's build applies WartRemover errors viaThisBuild; without the plugin here, the-P:wartremovercompiler options fail with "bad option". - smithy4s version is 0.18.55 (matching ADK4S) — the codegen output must match the runtime smithy4s jar on the classpath (which comes from ADK4S transitively).
The four ADK4S projects referenced:
adk4s-core—ChatModel,Embedder,Retrieverstructured-llm—StructuredLLM,Prompt,Schemaadk4s-memory-api—AgentMemory,Episode,EpisodeOutcome,MemoryHit,TemporalScope,SourceTypeadk4s-memory-testkit—AgentMemoryLaws(main scope; consumed by episode's Test scope via"test->compile")- The
episodemodule also depends onneo4j % "test->test"so its tests can useInMemoryGraphStore(which lives inneo4jTest scope) forAgentMemoryLawsconformance testing.
domain ─┬─ neo4j ─┐
├─ embedder(→ adk4s-core) ┤
├─ temporal ┤
└─ search ─┴─ episode(→ adk4s-core, structured-llm, adk4s-memory-api) ── api
config depends on domain, neo4j; telemetry on domain; core on
domain. The smithy IDL for the HTTP API lives in smithy/src/main/smithy/
(consumed by api via Smithy4sCodegenPlugin). The episode module has its own
smithy IDL at modules/episode/src/main/smithy/extraction.smithy for the
extraction DTOs (consumed by episode via Smithy4sCodegenPlugin).
configadds aneo4jdependency so it can referenceNeo4jConfig(the doc lists onlydomain, which would not compile).Neo4jGraphStore.resourceis implemented — creates a neotypesAsyncDriverfromNeo4jConfigand yieldsNeo4jGraphStoreImpl. All 13GraphStoremethods are implemented with parameterized Cypher.Instantvalues are stored as epoch-millis;Mapproperties are JSON-encoded as strings. Tests use Testcontainers with a shared container and a serializingSemaphoreto prevent parallel interference.EpisodeProcessor.builduses aname -> NodeIdmap (fixing the §8.2 known-gap: matching onlabels.contains(name)was wrong becauselabelsholds entity types, not names).InMemoryGraphStorelives inneo4jTest scope; downstream modules' tests that need it must adddependsOn(neo4j % Test)or extract atestkitmodule.- Extraction DTOs (
ExtractedEntity,ExtractedRelationship, etc.) are generated by smithy4s codegen fromextraction.smithy, not hand-written as case classes. This matches ADK4S's own pattern (structured-llm-test-models). smithy4s generates optional fields asOption[T]and renames reserved words (object→_object). Schema.instancesignature confirmed:instance(smithy: String, desc: Option[String] = None)(using SmithySchema[A]).MemoryHithasvalidFrom/validTofields (both defaultNone);GraphStoreMemory.toHitpopulatestext,score,provenance,payload.GraphStoreServer.buildusesSimpleRestJsonBuilder.routes(impl)to convert the smithy4s service implementation intoHttpRoutes[F], then wires them into anEmberServerBuilder. The@nowarn("cat=deprecation")was removed because the current wiring no longer triggers deprecation warnings.