{"templateId":"markdown","sharedDataIds":{},"props":{"metadata":{"markdoc":{"tagList":[]},"type":"markdown"},"seo":{"title":"Why Developers CAN Build Osmosis-Style Systems with Papr","siteUrl":"https://platform.papr.ai","description":"Papr Memory is an AI-native memory layer that lets developers add production-ready memory to their AI agents and apps with just a few lines of code."},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"why-developers-can-build-osmosis-style-systems-with-papr"},"children":["Why Developers CAN Build Osmosis-Style Systems with Papr"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Question:"]}," Why can't a developer just create a schema with a \"Claim\" node type that tracks claims and implements the governance features Osmosis needs?"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Answer:"]}," ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["They absolutely can."]}," That's exactly what Papr's custom schema system is designed for."]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"the-key-insight"},"children":["The Key Insight"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The developer's questions suggest they're thinking about ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["what"]}," they need (conflict detection, versioning, corroboration) when they should first consider ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["where to store the data"]}," that enables those features."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Papr provides the \"where\":"]}]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Knowledge graph for storing claims and relationships"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Custom schemas for defining domain models"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Node constraints for property injection"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["GraphQL for complex queries"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["The developer builds the \"what\":"]}]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Logic that uses those queries to detect conflicts"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Services that compute corroboration scores"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Rules that resolve contradictions"]}]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"concrete-example-why-it-works"},"children":["Concrete Example: Why It Works"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"1."},"children":["1. ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Create Custom Schema"]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"python","header":{"controls":{"copy":{}}},"source":"from papr_memory import Papr\n\nclient = Papr(x_api_key=\"your_api_key\")\n\n# Define EXACTLY what a Claim is in your domain\nschema = client.schemas.create(\n    name=\"Documentary Claims Tracking\",\n    description=\"Schema for evidence-based documentary knowledge\",\n    \n    node_types={\n        # First-class Claim node type\n        \"Claim\": {\n            \"name\": \"Claim\",\n            \"label\": \"Claim\",\n            \"description\": \"A factual assertion extracted from sources\",\n            \"properties\": {\n                # Core claim components (RDF-style triple)\n                \"subject\": {\n                    \"type\": \"string\",\n                    \"required\": True,\n                    \"description\": \"What the claim is about\"\n                },\n                \"predicate\": {\n                    \"type\": \"string\", \n                    \"required\": True,\n                    \"description\": \"The relationship or property\"\n                },\n                \"object\": {\n                    \"type\": \"string\",\n                    \"required\": True,\n                    \"description\": \"The value or target\"\n                },\n                \n                # Full statement for readability\n                \"statement\": {\n                    \"type\": \"string\",\n                    \"required\": True,\n                    \"description\": \"Human-readable claim text\"\n                },\n                \n                # Confidence metrics\n                \"extraction_confidence\": {\n                    \"type\": \"float\",\n                    \"default\": 0.0,\n                    \"description\": \"LLM confidence in extraction (0-1)\"\n                },\n                \"source_count\": {\n                    \"type\": \"integer\",\n                    \"default\": 1,\n                    \"description\": \"Number of sources supporting this claim\"\n                },\n                \"corroboration_score\": {\n                    \"type\": \"float\",\n                    \"default\": 0.0,\n                    \"description\": \"Multi-source corroboration strength (0-1)\"\n                },\n                \n                # Provenance\n                \"extracted_from_document\": {\n                    \"type\": \"string\",\n                    \"description\": \"Source document ID\"\n                },\n                \"extracted_from_page\": {\n                    \"type\": \"integer\",\n                    \"description\": \"Source page number\"\n                },\n                \"extracted_at\": {\n                    \"type\": \"datetime\",\n                    \"description\": \"When extraction occurred\"\n                },\n                \n                # Versioning\n                \"as_of_version\": {\n                    \"type\": \"string\",\n                    \"description\": \"Document/API version this claim comes from\"\n                },\n                \"temporal_scope\": {\n                    \"type\": \"string\",\n                    \"enum_values\": [\"historical\", \"current\", \"future\"],\n                    \"description\": \"Temporal validity of claim\"\n                },\n                \n                # Governance\n                \"conflict_status\": {\n                    \"type\": \"string\",\n                    \"enum_values\": [\"none\", \"potential\", \"confirmed\", \"resolved\"],\n                    \"default\": \"none\"\n                },\n                \"reviewed\": {\n                    \"type\": \"boolean\",\n                    \"default\": False,\n                    \"description\": \"Human review status\"\n                },\n                \"authoritative\": {\n                    \"type\": \"boolean\",\n                    \"default\": False,\n                    \"description\": \"Marked as authoritative/canonical\"\n                }\n            },\n            \"required_properties\": [\"subject\", \"predicate\", \"object\", \"statement\"],\n            \"unique_identifiers\": [\"subject\", \"predicate\", \"object\"]  # Dedupe on triple\n        },\n        \n        # Source tracking\n        \"DocumentSource\": {\n            \"name\": \"DocumentSource\",\n            \"label\": \"Document Source\",\n            \"properties\": {\n                \"document_id\": {\"type\": \"string\", \"required\": True},\n                \"document_title\": {\"type\": \"string\"},\n                \"version\": {\"type\": \"string\"},\n                \"publication_date\": {\"type\": \"datetime\"},\n                \"authority_level\": {\n                    \"type\": \"string\",\n                    \"enum_values\": [\"official\", \"draft\", \"unofficial\", \"third_party\"]\n                },\n                \"document_type\": {\n                    \"type\": \"string\",\n                    \"enum_values\": [\"specification\", \"contract\", \"report\", \"article\", \"email\"]\n                }\n            },\n            \"unique_identifiers\": [\"document_id\"]\n        },\n        \n        # Conflict tracking\n        \"ConflictSet\": {\n            \"name\": \"ConflictSet\",\n            \"label\": \"Conflict Set\",\n            \"description\": \"Group of claims that conflict with each other\",\n            \"properties\": {\n                \"subject\": {\"type\": \"string\", \"required\": True},\n                \"predicate\": {\"type\": \"string\", \"required\": True},\n                \"detected_at\": {\"type\": \"datetime\"},\n                \"resolution_status\": {\n                    \"type\": \"string\",\n                    \"enum_values\": [\"unresolved\", \"resolved\", \"acknowledged\", \"ignored\"]\n                },\n                \"resolution_method\": {\n                    \"type\": \"string\",\n                    \"description\": \"How conflict was resolved (e.g., 'most_recent', 'highest_authority')\"\n                },\n                \"resolved_at\": {\"type\": \"datetime\"},\n                \"resolved_by\": {\"type\": \"string\"},\n                \"notes\": {\"type\": \"string\"}\n            }\n        },\n        \n        # Version tracking\n        \"KnowledgeVersion\": {\n            \"name\": \"KnowledgeVersion\",\n            \"label\": \"Knowledge Version\",\n            \"description\": \"Temporal version of knowledge about a subject\",\n            \"properties\": {\n                \"subject\": {\"type\": \"string\", \"required\": True},\n                \"version\": {\"type\": \"string\", \"required\": True},\n                \"effective_from\": {\"type\": \"datetime\"},\n                \"effective_until\": {\"type\": \"datetime\"},\n                \"superseded\": {\"type\": \"boolean\", \"default\": False}\n            }\n        }\n    },\n    \n    relationship_types={\n        # Provenance relationships\n        \"EXTRACTED_FROM\": {\n            \"name\": \"EXTRACTED_FROM\",\n            \"allowed_source_types\": [\"Claim\"],\n            \"allowed_target_types\": [\"DocumentSource\"],\n            \"properties\": {\n                \"page_number\": {\"type\": \"integer\"},\n                \"section\": {\"type\": \"string\"},\n                \"extraction_method\": {\n                    \"type\": \"string\",\n                    \"enum_values\": [\"llm\", \"manual\", \"structured\"]\n                }\n            }\n        },\n        \n        # Conflict relationships\n        \"CONFLICTS_WITH\": {\n            \"name\": \"CONFLICTS_WITH\",\n            \"allowed_source_types\": [\"Claim\"],\n            \"allowed_target_types\": [\"Claim\"],\n            \"properties\": {\n                \"conflict_type\": {\n                    \"type\": \"string\",\n                    \"enum_values\": [\"direct_contradiction\", \"incompatible_values\", \"temporal_inconsistency\"]\n                },\n                \"detected_at\": {\"type\": \"datetime\"}\n            }\n        },\n        \n        \"MEMBER_OF\": {\n            \"name\": \"MEMBER_OF\",\n            \"allowed_source_types\": [\"Claim\"],\n            \"allowed_target_types\": [\"ConflictSet\"]\n        },\n        \n        # Support relationships\n        \"SUPPORTS\": {\n            \"name\": \"SUPPORTS\",\n            \"allowed_source_types\": [\"Claim\"],\n            \"allowed_target_types\": [\"Claim\"],\n            \"properties\": {\n                \"support_type\": {\n                    \"type\": \"string\",\n                    \"enum_values\": [\"corroborates\", \"provides_evidence\", \"logical_entailment\"]\n                },\n                \"confidence\": {\"type\": \"float\"}\n            }\n        },\n        \n        \"REFUTES\": {\n            \"name\": \"REFUTES\",\n            \"allowed_source_types\": [\"Claim\"],\n            \"allowed_target_types\": [\"Claim\"]\n        },\n        \n        # Version relationships\n        \"VERSION_OF\": {\n            \"name\": \"VERSION_OF\",\n            \"allowed_source_types\": [\"Claim\"],\n            \"allowed_target_types\": [\"KnowledgeVersion\"]\n        },\n        \n        \"SUPERSEDES\": {\n            \"name\": \"SUPERSEDES\",\n            \"allowed_source_types\": [\"KnowledgeVersion\"],\n            \"allowed_target_types\": [\"KnowledgeVersion\"],\n            \"properties\": {\n                \"change_type\": {\n                    \"type\": \"string\",\n                    \"enum_values\": [\"correction\", \"update\", \"deprecation\", \"clarification\"]\n                }\n            }\n        }\n    }\n)\n\nprint(f\"Schema created: {schema.data.id}\")\n","lang":"python"},"children":[]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"2."},"children":["2. ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Extract Claims from Documents"]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"python","header":{"controls":{"copy":{}}},"source":"# Upload document - Papr extracts claims automatically\nresponse = client.document.upload(\n    file=open(\"api_specification_v2.pdf\", \"rb\"),\n    schema_id=schema.data.id,\n    metadata={\n        \"version\": \"v2.0\",\n        \"authority\": \"official\",\n        \"document_type\": \"specification\"\n    }\n)\n\n# OR add claim explicitly with full control\nresponse = client.memory.add(\n    content=\"The API rate limit is 1000 requests per hour according to section 3.2 of the v2.0 specification\",\n    memory_policy={\n        \"mode\": \"auto\",  # Let LLM extract entities\n        \"schema_id\": schema.data.id,\n        \n        # Force specific properties on extracted Claim node\n        \"node_constraints\": [\n            {\n                \"node_type\": \"Claim\",\n                \"set\": {\n                    \"subject\": \"API rate limit\",\n                    \"predicate\": \"is\",\n                    \"object\": \"1000 requests per hour\",\n                    \"statement\": \"The API rate limit is 1000 requests per hour\",\n                    \"as_of_version\": \"v2.0\",\n                    \"extracted_from_document\": \"api_spec_v2\",\n                    \"extracted_from_page\": 12,\n                    \"extracted_at\": datetime.now().isoformat(),\n                    \"extraction_confidence\": 0.95,\n                    \"temporal_scope\": \"current\"\n                }\n            },\n            {\n                \"node_type\": \"DocumentSource\",\n                \"set\": {\n                    \"document_id\": \"api_spec_v2\",\n                    \"version\": \"v2.0\",\n                    \"authority_level\": \"official\",\n                    \"document_type\": \"specification\"\n                }\n            }\n        ]\n    }\n)\n","lang":"python"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["What just happened:"]}]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Claim node created with ALL the properties you need for governance"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["DocumentSource node created (or linked if exists)"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["EXTRACTED_FROM relationship automatically created"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Full provenance chain established"]}]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"3."},"children":["3. ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Detect Conflicts with GraphQL"]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"python","header":{"controls":{"copy":{}}},"source":"# Query all claims about same subject+predicate\nconflict_query = \"\"\"\nquery FindPotentialConflicts($subject: String!, $predicate: String!) {\n  claims(where: {\n    subject: $subject,\n    predicate: $predicate\n  }) {\n    id\n    statement\n    object\n    as_of_version\n    extraction_confidence\n    extracted_from {\n      document_id\n      version\n      authority_level\n    }\n  }\n}\n\"\"\"\n\n# Execute query\nresult = await client.graphql.query(\n    query=conflict_query,\n    variables={\n        \"subject\": \"API rate limit\",\n        \"predicate\": \"is\"\n    }\n)\n\n# Analyze results\nclaims = result['data']['claims']\nunique_values = set(claim['object'] for claim in claims)\n\nif len(unique_values) > 1:\n    print(f\"⚠️ CONFLICT DETECTED: {len(unique_values)} different values\")\n    for claim in claims:\n        print(f\"  - '{claim['object']}' from {claim['extracted_from']['document_id']} (v{claim['extracted_from']['version']})\")\n    \n    # Create conflict set\n    conflict_response = await client.memory.add(\n        content=f\"Conflict detected for '{subject}' {predicate}\",\n        memory_policy={\n            \"mode\": \"manual\",\n            \"nodes\": [\n                {\n                    \"id\": \"conflict_set_1\",\n                    \"type\": \"ConflictSet\",\n                    \"properties\": {\n                        \"subject\": subject,\n                        \"predicate\": predicate,\n                        \"detected_at\": datetime.now().isoformat(),\n                        \"resolution_status\": \"unresolved\"\n                    }\n                }\n            ],\n            \"relationships\": [\n                {\n                    \"source\": claim['id'],\n                    \"target\": \"conflict_set_1\",\n                    \"type\": \"MEMBER_OF\"\n                }\n                for claim in claims\n            ]\n        }\n    )\n","lang":"python"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Why this works:"]}]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Your schema defines EXACTLY what properties each Claim has"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["GraphQL lets you query by those properties"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["You can group by (subject, predicate) to find conflicts"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["ConflictSet nodes track resolution status"]}]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"4."},"children":["4. ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Compute Corroboration Scores"]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"python","header":{"controls":{"copy":{}}},"source":"# Service that runs periodically\nasync def update_corroboration_scores():\n    \"\"\"Count how many sources support each claim.\"\"\"\n    \n    # Get all claims with their sources\n    query = \"\"\"\n    query GetClaimSources {\n      claims {\n        id\n        subject\n        predicate\n        object\n        extracted_from {\n          document_id\n          authority_level\n        }\n      }\n    }\n    \"\"\"\n    \n    result = await client.graphql.query(query)\n    \n    # Group claims by (subject, predicate, object) triple\n    claim_groups = {}\n    for claim in result['data']['claims']:\n        key = (claim['subject'], claim['predicate'], claim['object'])\n        if key not in claim_groups:\n            claim_groups[key] = []\n        claim_groups[key].append(claim)\n    \n    # Update each claim's corroboration score\n    for (subject, predicate, obj), claims in claim_groups.items():\n        source_count = len(set(c['extracted_from']['document_id'] for c in claims))\n        \n        # Weight by authority level\n        official_sources = sum(1 for c in claims if c['extracted_from']['authority_level'] == 'official')\n        \n        # Compute score (example formula)\n        corroboration_score = min((source_count * 0.2) + (official_sources * 0.3), 1.0)\n        \n        # Update all claims in this group\n        for claim in claims:\n            await client.memory.add(\n                content=f\"Corroboration update for claim {claim['id']}\",\n                memory_policy={\n                    \"mode\": \"manual\",\n                    \"node_constraints\": [\n                        {\n                            \"node_type\": \"Claim\",\n                            \"search\": {\n                                \"properties\": [\n                                    {\"name\": \"id\", \"mode\": \"exact\", \"value\": claim['id']}\n                                ]\n                            },\n                            \"set\": {\n                                \"source_count\": source_count,\n                                \"corroboration_score\": corroboration_score\n                            }\n                        }\n                    ]\n                }\n            )\n        \n        print(f\"✅ Updated corroboration for '{subject} {predicate} {obj}': {source_count} sources, score={corroboration_score}\")\n","lang":"python"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Why this works:"]}]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["You stored source_count and corroboration_score in your Claim schema"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["GraphQL lets you query all claims with their sources"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["You compute the score using whatever formula makes sense"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Node constraints let you update specific claims by ID"]}]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"5."},"children":["5. ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Track Version History"]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"python","header":{"controls":{"copy":{}}},"source":"# Create version nodes as knowledge evolves\nasync def track_version_change(subject, old_version, new_version, change_type):\n    \"\"\"Track that knowledge changed from one version to another.\"\"\"\n    \n    response = await client.memory.add(\n        content=f\"Version transition: {subject} changed from {old_version} to {new_version}\",\n        memory_policy={\n            \"mode\": \"manual\",\n            \"nodes\": [\n                {\n                    \"id\": f\"version_{old_version}\",\n                    \"type\": \"KnowledgeVersion\",\n                    \"properties\": {\n                        \"subject\": subject,\n                        \"version\": old_version,\n                        \"effective_until\": datetime.now().isoformat(),\n                        \"superseded\": True\n                    }\n                },\n                {\n                    \"id\": f\"version_{new_version}\",\n                    \"type\": \"KnowledgeVersion\",\n                    \"properties\": {\n                        \"subject\": subject,\n                        \"version\": new_version,\n                        \"effective_from\": datetime.now().isoformat(),\n                        \"superseded\": False\n                    }\n                }\n            ],\n            \"relationships\": [\n                {\n                    \"source\": f\"version_{new_version}\",\n                    \"target\": f\"version_{old_version}\",\n                    \"type\": \"SUPERSEDES\",\n                    \"properties\": {\n                        \"change_type\": change_type\n                    }\n                }\n            ]\n        }\n    )\n\n# Query version history\nversion_history_query = \"\"\"\nquery GetVersionHistory($subject: String!) {\n  knowledge_versions(\n    where: { subject: $subject }\n    order_by: { effective_from: ASC }\n  ) {\n    version\n    effective_from\n    effective_until\n    superseded\n    supersedes {\n      version\n    }\n    claims {\n      statement\n      object\n    }\n  }\n}\n\"\"\"\n\nhistory = await client.graphql.query(\n    query=version_history_query,\n    variables={\"subject\": \"API rate limit\"}\n)\n\n# Result:\n# v1.0: \"100 requests/hour\" (2024-01-01 to 2025-06-01) [superseded]\n#   └─> superseded by v2.0\n# v2.0: \"1000 requests/hour\" (2025-06-01 to present) [current]\n","lang":"python"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Why this works:"]}]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["KnowledgeVersion nodes explicitly model temporal scope"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["SUPERSEDES relationships create version chains"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["effective_from/effective_until enable point-in-time queries"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Claims link to versions via VERSION_OF relationship"]}]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"6."},"children":["6. ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Point-in-Time Queries"]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"python","header":{"controls":{"copy":{}}},"source":"# What did we know about X on date Y?\nasync def get_knowledge_at_time(subject: str, timestamp: datetime):\n    \"\"\"Get what we knew about subject at specific time.\"\"\"\n    \n    query = \"\"\"\n    query PointInTimeKnowledge($subject: String!, $timestamp: DateTime!) {\n      knowledge_versions(where: {\n        subject: $subject,\n        effective_from: { $lte: $timestamp },\n        effective_until: { $gte: $timestamp }\n      }) {\n        version\n        claims {\n          statement\n          object\n          corroboration_score\n          sources {\n            document_id\n            authority_level\n          }\n        }\n      }\n    }\n    \"\"\"\n    \n    result = await client.graphql.query(\n        query=query,\n        variables={\n            \"subject\": subject,\n            \"timestamp\": timestamp.isoformat()\n        }\n    )\n    \n    return result['data']['knowledge_versions']\n\n# Example usage\nmarch_2025_knowledge = await get_knowledge_at_time(\n    subject=\"API rate limit\",\n    timestamp=datetime(2025, 3, 1)\n)\n\nprint(f\"In March 2025, we knew: {march_2025_knowledge[0]['claims'][0]['statement']}\")\n# Output: \"In March 2025, we knew: The API rate limit is 100 requests per hour\"\n","lang":"python"},"children":[]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"why-the-developer-can-build-this"},"children":["Why The Developer Can Build This"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"1.-"},"children":["1. ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Full Schema Control"]}," ✅"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"python","header":{"controls":{"copy":{}}},"source":"# You define EXACTLY what properties claims have\n\"Claim\": {\n    \"properties\": {\n        \"subject\": ...,\n        \"predicate\": ...,\n        \"object\": ...,\n        \"confidence\": ...,\n        \"source_count\": ...,\n        # ANY properties you need for governance\n    }\n}\n","lang":"python"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"2.-"},"children":["2. ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Property Injection"]}," ✅"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"python","header":{"controls":{"copy":{}}},"source":"# Force metadata onto every extracted node\n\"node_constraints\": [{\n    \"node_type\": \"Claim\",\n    \"set\": {\n        \"extracted_at\": datetime.now(),\n        \"version\": \"v2.0\",\n        \"reviewed\": False\n        # Whatever you need\n    }\n}]\n","lang":"python"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"3.-"},"children":["3. ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Relationship Modeling"]}," ✅"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"python","header":{"controls":{"copy":{}}},"source":"# Model ANY relationship type\n\"relationship_types\": {\n    \"CONFLICTS_WITH\": {...},\n    \"SUPPORTS\": {...},\n    \"SUPERSEDES\": {...}\n    # Define what makes sense for your domain\n}\n","lang":"python"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"4.-"},"children":["4. ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["GraphQL Queries"]}," ✅"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"python","header":{"controls":{"copy":{}}},"source":"# Complex analytics queries\nquery = \"\"\"\nquery ConflictAnalysis {\n  conflict_sets(where: { resolution_status: \"unresolved\" }) {\n    claims {\n      object\n      sources {\n        authority_level\n      }\n    }\n  }\n}\n\"\"\"\n","lang":"python"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"5.-"},"children":["5. ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Provenance Built-In"]}," ✅"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Every memory automatically has:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["memory_id"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["created_at"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["source"]}," (document/message that created it)"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Link to original content"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"6.-"},"children":["6. ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Entity Resolution"]}," ✅"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["\"API rate limit\" mentioned in 10 documents → Papr merges into one node automatically"]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"what-makes-this-different-from-diy"},"children":["What Makes This Different from DIY"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"if-you-build-from-scratch"},"children":["If You Build from Scratch:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"python","header":{"controls":{"copy":{}}},"source":"# You'd need to implement:\n- Graph database (Neo4j setup, indexes, backups)\n- Vector embeddings (model selection, embedding generation)\n- Hybrid search (BM25 + vector + graph ranking)\n- Entity resolution (fuzzy matching, deduplication)\n- Schema validation (custom code)\n- GraphQL server (schema generation, resolvers)\n- API layer (authentication, rate limiting)\n- Multi-tenancy (data isolation)\n\n# Time: 6-12 months\n# Cost: $200k+ in engineering\n","lang":"python"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"with-papr"},"children":["With Papr:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"python","header":{"controls":{"copy":{}}},"source":"# You implement:\n- Schema design (your domain model)\n- Governance services (conflict detection, scoring)\n- Resolution rules (your business logic)\n\n# Time: 8-10 weeks\n# Cost: ~$1,200/month + developer time\n","lang":"python"},"children":[]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"the-crucial-insight"},"children":["The Crucial Insight"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Papr isn't trying to be a complete governance system."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["It's providing the ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["primitives"]}," you need to build one:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"header":{"controls":{"copy":{}}},"source":"┌─────────────────────────────────────┐\n│  YOUR GOVERNANCE LOGIC              │  ← You build this\n│  • Conflict detection               │\n│  • Corroboration scoring            │\n│  • Resolution rules                 │\n└─────────────────────────────────────┘\n               ↕\n┌─────────────────────────────────────┐\n│  PAPR PRIMITIVES                    │  ← We provide this\n│  • Knowledge graph                  │\n│  • Custom schemas                   │\n│  • Property injection               │\n│  • GraphQL queries                  │\n│  • Entity resolution                │\n│  • Provenance tracking              │\n└─────────────────────────────────────┘\n"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["The governance layer is domain-specific."]}," Every system has different:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Conflict resolution strategies"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Authority hierarchies"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Versioning semantics"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Corroboration formulas"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["You wouldn't want Papr to hard-code these."]}," You want flexibility to model your domain."]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"why-schema-system-is-powerful"},"children":["Why Schema System is Powerful"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Compare to other databases:"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"postgresql"},"children":["PostgreSQL:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"sql","header":{"controls":{"copy":{}}},"source":"CREATE TABLE claims (\n  id UUID PRIMARY KEY,\n  subject TEXT,\n  predicate TEXT,\n  object TEXT\n  -- But no automatic entity resolution\n  -- No graph relationships\n  -- No semantic search\n);\n","lang":"sql"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"neo4j-bare"},"children":["Neo4j (bare):"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"cypher","header":{"controls":{"copy":{}}},"source":"CREATE (c:Claim {subject: \"...\", predicate: \"...\"})\n-- But no schema validation\n-- No automatic extraction\n-- No semantic search\n-- No hybrid retrieval\n","lang":"cypher"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"papr"},"children":["Papr:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"python","header":{"controls":{"copy":{}}},"source":"schema = client.schemas.create(\n    node_types={\"Claim\": {...}},\n    relationship_types={\"CONFLICTS_WITH\": {...}}\n)\n# Gets you:\n# ✅ Schema validation\n# ✅ Entity resolution\n# ✅ Semantic search\n# ✅ Graph relationships\n# ✅ Hybrid retrieval\n# ✅ GraphQL queries\n# All in one API\n","lang":"python"},"children":[]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"summary"},"children":["Summary"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Q: Why can't they just create a Claim schema?"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["A: They absolutely can. That's the point."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Papr's custom schema system lets you define EXACTLY what your domain needs:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["What node types exist (Claim, Source, ConflictSet, etc.)"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["What properties they have (confidence, version, authority, etc.)"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["What relationships connect them (EXTRACTED_FROM, CONFLICTS_WITH, etc.)"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["How to match/dedupe (unique_identifiers, node_constraints)"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Then you get:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Storage (graph database)"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Retrieval (hybrid search)"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Analytics (GraphQL)"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Provenance (automatic tracking)"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Entity resolution (auto-merging)"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["All automatically."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["What you still build:"]}]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Services that USE those queries for conflict detection"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Logic that COMPUTES corroboration scores"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Rules that RESOLVE contradictions"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["UI that DISPLAYS governance status"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["But that's domain logic you'd write regardless of underlying database."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["The question isn't \"can you do this with Papr?\""]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["The question is \"do you want to build the database layer yourself, or focus on governance logic?\""]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Papr = focus on governance. DIY = build database first, then governance."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Time saved: 6-12 months."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["That's why they can (and should) build Osmosis on Papr."]}]},"headings":[{"value":"Why Developers CAN Build Osmosis-Style Systems with Papr","id":"why-developers-can-build-osmosis-style-systems-with-papr","depth":1},{"value":"The Key Insight","id":"the-key-insight","depth":2},{"value":"Concrete Example: Why It Works","id":"concrete-example-why-it-works","depth":2},{"value":"1.","id":"1.","depth":3},{"value":"2.","id":"2.","depth":3},{"value":"3.","id":"3.","depth":3},{"value":"4.","id":"4.","depth":3},{"value":"5.","id":"5.","depth":3},{"value":"6.","id":"6.","depth":3},{"value":"Why The Developer Can Build This","id":"why-the-developer-can-build-this","depth":2},{"value":"1. ✅","id":"1.-","depth":3},{"value":"2. ✅","id":"2.-","depth":3},{"value":"3. ✅","id":"3.-","depth":3},{"value":"4. ✅","id":"4.-","depth":3},{"value":"5. ✅","id":"5.-","depth":3},{"value":"6. ✅","id":"6.-","depth":3},{"value":"What Makes This Different from DIY","id":"what-makes-this-different-from-diy","depth":2},{"value":"If You Build from Scratch:","id":"if-you-build-from-scratch","depth":3},{"value":"With Papr:","id":"with-papr","depth":3},{"value":"The Crucial Insight","id":"the-crucial-insight","depth":2},{"value":"Why Schema System is Powerful","id":"why-schema-system-is-powerful","depth":2},{"value":"PostgreSQL:","id":"postgresql","depth":3},{"value":"Neo4j (bare):","id":"neo4j-bare","depth":3},{"value":"Papr:","id":"papr","depth":3},{"value":"Summary","id":"summary","depth":2}],"frontmatter":{"seo":{"title":"Why Developers CAN Build Osmosis-Style Systems with Papr"}},"lastModified":"2026-04-22T01:40:48.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/internal/planning/osmosis-why-it-works","userData":{"isAuthenticated":false,"teams":["anonymous"]}}