Semantic Flow General Guidance
Semantic Flow is a framework for managing knowledge graphs and other Semantic Web resources in publish-ready semantic meshes
Developer Workflow
- Build/Watch:
- The development workflow requires two terminals running concurrently:
- Terminal 1: Run
pnpm dev:watch
to start the TypeScript compiler in watch mode. This will watch all packages and rebuild them on change. - Terminal 2: Run
pnpm dev
to start thenodemon
server, which will automatically restart when the built files in thedist
directories are updated.
- Terminal 1: Run
- This setup ensures that changes in any package are automatically compiled and that the server restarts with the latest code.
- Keep inter-package imports as package specifiers; avoid deep source imports across packages.
- The development workflow requires two terminals running concurrently:
Workspace Components
- The sflow-platform repo/folder is organized as a monorepo, divided into a few different modules:
- sflo-host/: host service with plugin architecture
- sflo-api/: plugin providing Semantic Flow functionality via REST
- cli/: Command-line application that consumes the sflo-api
- sflo-web/: Web frontend, can connect to any sflo-api instance
- shared/: cross-cutting code like type schemas (core), logging, and config
- test-ns/ repo: Test mesh repo
- ontology/: repo containing relevant ontologies:
mesh
- Core mesh architecture with base classes (Resource, Node, Component) and fundamental typesnode
- Node operations including Handle, Flow types, and operational relationshipsflow
- Temporal concepts including Snapshot types and versioning relationshipsconfig-flow
- Configuration properties that apply directly to mesh entities (nodes, flows, snapshots, etc.)meta-flow
- provenance and licensing vocabularyflow-service
- Service layer configuration vocabulary for the flow-service application
Key Concepts
Semantic Mesh
A dereferenceable, versioned collection of semantic data and supporting resources, where every HTTP URI returns meaningful content. See semantic mesh
Core Components
- Mesh Resources:
- Nodes: Semantic Atoms
- data nodes: Bundles of data with optional quasi-immutable, versioned history
- bare nodes: basically empty folders for URL-based hierarchical organization
- Components: things that help define and systematize the nodes
- Flows: datasets for node metadata and data
- Snapshots: temporal slices of a flow, containing RDF dataset distributions
- Handles: things that let you refer to a node as a node instead of as its referent
- Asset Trees: components that allow you to attach arbitrary collections of files and folders to a mesh; in a sense, these things are "outside" the mesh, and other than the top-level "_meta" folder, they don't contain any other mesh resources
- Flows: datasets for node metadata and data
- Nodes: Semantic Atoms
Semantic Flow Workflow:
- In General: Mesh resource addition & editing → Weaving
- a mesh is servable "as-is", so if the git provider is configure to serve it as a website, no additional publishing step is required (beyond commit)
Semantic Site
- The repo IS the site:
- can be served locally
- no separate SSG (Static Site Generator) necessary
- but static resource page generation should happen on every weave as necessary
- after push, you should be able to see the changed mesh at the corresponding github pages URL
RDF and Semantic Web
- avoid use of blank nodes
- prefer relative/local URIs for transposability/composability
- meshes support multiple RDF formats (.trig, .jsonld, etc.)
- .trig might be better for user-facing content
- .jsonld might be better for system content
- be mindful of RDF terminology and concepts
- extends DCAT for dataset catalogs
- extends PROV for provenance, with relator-based contexts
- When referring to IRIs or URIs that are part of a semantic mesh, prefer the term URLs instead of IRI or URI
- if you see a reference to IRI or URI, it might need updating, or it might mean a distinction should be drawn
- RDF comments should be extremely concise and clear.
Quadstore
- make sure you are familiar with tech-stack.quadstore.readme (Private), which documents the API
- For testability and in case we ever want to use multiple stores simultaneously, store-accessing functions take a QuadstoreBundle
- quadstore API calls use "undefined" instead of "null" to represent the wildcard for subjects, predicates, objects, and graphs
Documentation
- Avoid numbering of code comments, headings and list items, as it makes re-ordering a pain
- All specifications and design docs are in
sflo-dendron-notes/
- Check conversation logs in
sflo.conv.*
for context on design decisions if necessary, but beware of superceded and dangerously-outdated info
Documentation First
- unclear or anemic documentation should be called out
- documentation should be wiki-style: focused on the topic at hand, don't repeat yourself, keep things simple and clear
- when assisting with writing documentation, it should be kept concise and specific to the topic at hand
- whenever documentation is updated, any corresponding LLM conversation context should be updated too
- to encourage documentation-driven software engineering, code comments should refer to corresponding documentation by filename, and the documentation and code should be cross-checked for consistency whenever possible
Documentation Architecture
sflo-dendron-notes
repo has wiki-style notes about the mesh architecture- Dendron handles the frontmatter... don't rewrite IDs or anything else in the frontmatter
- official project documentation should be generated in
documentation
directory in markdown
Project notes
Project documentation, specifications, and design choices are stored in documentation/
using Dendron's hierarchical note system. Key documentation hierarchies include:
- Concepts:
concept.*
files talk about general Semantic Flow concepts - Mesh docs:
concept.mesh.*
files define the semantic mesh architecture - Product specifications:
product.*
files detail each component - Use cases:
use-cases.*
for feature planning and testing
Component Development with Docs
- Each module (flow-cli, flow-service, flow-web) should follow the architecture defined in the documentation
- Refer to
sflo.product.*
files for component-specifc descriptions, requirements, etc
Project Architecture
Configuration Architecture
- The project uses a sophisticated JSON-LD based configuration system with multiple layers
- Service Configuration resolution order: CLI arguments → Environment variables → Config file → Defaults
- The
defaults.ts
file is the source for "platform default" configuration
Logging System Architecture
- Structured logging with rich
LogContext
interface is the preferred approach - Three-channel logging architecture:
- Console logging (pretty format for development)
- File logging (pretty format for human readability)
- Sentry logging (structured JSON for error tracking)
- Graceful degradation principle: Logging failures should never crash the application
Logging System Patterns
let logger = getComponentLogger(import.meta);
at the start of every file
Error Handling Patterns
- Use the
handleCaughtError
utility for consistent error handling - Documentation: See error-handling-usage.md for comprehensive usage examples
- The error handling system integrates with all logging tiers (console, file, Sentry)
File Organization
- Import paths require careful attention when reorganizing files to avoid breaking dependencies
Implementation Patterns
- Proper TypeScript interfaces for configuration validation and type safety
- SHACL constraints for JSON-LD validation when working with semantic data
- Modular design: Keep utilities focused and avoid circular dependencies between core modules
Coding Standards
Language & Runtime
- TypeScript: Use strict TypeScript configuration with modern ES2022+ features
- Use NodeJS v24 and the latest best practices
RDF Data Handling
- Primary Format: .trig files for RDF data storage and processing
- Secondary Format: Full JSON-LD support required
- RDF Libraries: Use RDF.js ecosystem libraries consistently across components
- Namespace Management: Follow URL-based identifier patterns as defined in
sflo.concept.identifier.md
- Reserved Names: Validate against underscore-prefixed reserved identifiers per
sflo.concept.identifier.md
- The most effective validation strategy combines TypeScript structural validation with RDF semantic validation:
Semantic Mesh Architecture
- Resource Types: Nodes are the foundation, Components support Nodes, Flows are "abstract datasets", and "Snapshots" are their temporal slices as defined in
sflo.concept.mesh.md
- Folder Structure: Validate mesh folder structures (data nodes, bare nodes, etc.)
- System Components: Distinguish between system-generated and user-modifiable components
- Weave Integration: Code must support weave operations as defined in
sflo.concept.weave.md
Documentation-Driven Development
- Code Comments: reference corresponding documentation by filename (e.g.,
// See sflo.concept.mesh.resource.node.md
) - Interface Definitions: Link to concept documentation in TSDoc comments
- Cross-Reference Validation: Ensure consistency between code and documentation; if docs need updating, let me know
- API Documentation: Generate from TSDoc comments?
Component Architecture
- Shared code: should go in flow-core/
- Separation: Maintain clear boundaries between flow-cli, flow-service, and flow-web
- Error Handling: Use consistent error patterns across all components
- Async Patterns: Use async/await for RDF operations and file I/O
- Type Safety: Leverage TypeScript's type system for mesh resource validation
File Organization & Naming
- TypeScript Modules: Use
.ts
extension, organize by feature/component - Test Files:
- unit test files go in tests/unit/ using
.test.ts
suffix - integration tests go in tests/integration
- unit test files go in tests/unit/ using
- Mesh Resources: Follow mesh resource naming conventions from @/ontology/alpha/_node-data/_next/flow-ontology-alpha.trig (Private)
- Constants: Use UPPER_SNAKE_CASE for constants, especially for reserved names; centralize constants, e.g. semantic-flow/flow-core/src/mesh-constants.ts
- File size: For ease of AI-based editing, prefer lots of small files over one huge file
- Quoting: For easier compatibility with JSON files, use double quotes everywhere
Import Path Policy
-
Inter-package imports (between workspace packages):
- Use workspace package specifiers.
- Examples:
import { startHost } from "@semantic-flow/host"
import { loadConfig } from "@semantic-flow/config"
- Rationale:
- Keeps package boundaries clear and publish-ready
- pnpm resolves to local workspace packages during development, so you get your local builds—not the registry
- Compatible with build/watch flows and CI
-
Intra-package imports (within a single package):
- Use the
@
alias mapped to that package’ssrc/
root to avoid relative path chains. - Example (inside a package):
import { something } from "@/features/something"
- Configuration (per package tsconfig):
"compilerOptions": { "baseUrl": "src", "paths": { "@/*": ["*"] } }
- Tooling notes:
- For Node/tsx/Vitest, ensure your runner resolves TS path aliases (e.g.,
tsconfig-paths/register
or vite-tsconfig-paths).
- For Node/tsx/Vitest, ensure your runner resolves TS path aliases (e.g.,
- Use the
- Publishing:
- Each package should export built entry points (e.g.,
dist/
) viaexports
/main
/types
. The same import paths work identically in dev and prod.
- Each package should export built entry points (e.g.,
Code Style
- If using any is actually clearer than not using it, it's okay, just add the // deno-lint-ignore comment
- Use
satisfies
whenever you're writing a literal config object that should be checked against a TypeScript shape, but you want to retain the full type of the literal for use in your program.
Error Handling
- Custom Errors: Create semantic mesh-specific error types
- Validation: Validate mesh resource structures before processing
- Logging: Use structured logging for debugging weave operations
- Async Error Propagation: Properly handle async/await error chains
Enhanced Error Handling with LogContext
The platform uses LogContext-enhanced error handling from flow-core/src/utils/logger/error-handlers.ts
for consistent error logging across all components. Both error handling functions now accept optional LogContext
parameters for rich contextual information.
Core Functions:
handleCaughtError()
- For caught exceptions with comprehensive error type handlinghandleError()
- For controlled error scenarios with structured messaging
LogContext Structure
handleCaughtError Examples
Startup Error Handling:
This pattern ensures uniform error reporting with rich contextual information, easier debugging through structured logging, and consistent integration with console, file, and Sentry logging tiers.
Testing
- Unit Tests: place unit tests in
src/__tests__
folder; with.test.ts
suffix; target ≥80% critical-path coverage and include both success and failure cases. - Integration Tests: Test mesh operations end-to-end; tests are located in test/integration/ dir
- RDF Validation: Test both .trig and JSON-LD parsing/serialization
- Mock Data: Create test mesh structures following documentation patterns
- after you think you've completed a task, check for any "problems", i.e., deno-lint
Performance
- RDF Processing: Stream large RDF files where possible
- File I/O: Use async file operations consistently