<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: opensource</title>
    <description>The latest articles tagged 'opensource' on DEV Community.</description>
    <link>https://dev.to/t/opensource</link>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tag/opensource"/>
    <language>en</language>
    <item>
      <title>Did GitHub change license enforcement in pull requests?</title>
      <dc:creator>Dev Connect</dc:creator>
      <pubDate>Mon, 24 Aug 2026 06:15:05 +0000</pubDate>
      <link>https://dev.to/devconnect/did-github-change-license-enforcement-in-pull-requests-2a1f</link>
      <guid>https://dev.to/devconnect/did-github-change-license-enforcement-in-pull-requests-2a1f</guid>
      <description>&lt;p&gt;&lt;strong&gt;Short answer:&lt;/strong&gt; Yes. GitHub now enforces open source license policy in pull requests through rulesets, comparing dependency changes against policy, annotating violations, and blocking merges when Active mode requires compliance.&lt;/p&gt;

&lt;p&gt;Yes. GitHub moved open source license enforcement into ruleset-based pull request checks for dependency changes. The current model compares the base branch and the pull request branch, evaluates detected licenses against policy, and then either annotates the pull request or blocks the merge when enforcement is active.&lt;/p&gt;

&lt;p&gt;The part people miss is scope. GitHub is not talking about every file in a repository or every line of application code. The license compliance feature is about dependencies, package manifests, and the licenses those manifests bring into the tree. GitHub’s docs say the check runs when a pull request changes package manifests and uses dependency graph data, including transitive dependencies.&lt;/p&gt;

&lt;p&gt;The enforcement model also changed in a practical way. GitHub documents two modes in rulesets: Evaluate and Active. Evaluate runs license checks and adds annotations without blocking merges. Active adds the requirement to merge only after compliance results pass, so a noncompliant dependency can keep the pull request blocked until the violation is fixed or an exception is approved.&lt;/p&gt;

&lt;p&gt;That is the part people often get wrong. GitHub did not simply add a warning banner to pull requests, and it did not make license review a manual-only approval step. The feature is policy-driven, tied to enterprise rulesets, and it can stop the merge when the policy says the dependency is not allowed. The pull request becomes the enforcement point, not just the review surface.&lt;/p&gt;

&lt;p&gt;The inconvenient part is that this is not available as a universal GitHub feature for all repositories. GitHub says open source license compliance is in public preview and is available for organizations on GitHub Enterprise Cloud with GitHub Code Security and, in the changelog, for customers with GitHub Advanced Security Code Security licenses. In other words, this is an enterprise governance feature, not a default setting for every public repo.&lt;/p&gt;

&lt;p&gt;Another detail people miss is that license compliance is policy plus exceptions. GitHub lets enterprise policy managers approve package, license, or package-pattern exceptions, and those exceptions can be applied at repository or enterprise scope. That means a blocked pull request is not always solved by rewriting code. Sometimes the fix is policy work, and sometimes it is an explicit exception request handled by the people who control the rules.&lt;/p&gt;

&lt;p&gt;If you are trying to understand the older behavior, the simplest answer is that GitHub has expanded from showing license information to enforcing license policy in the pull request flow. GitHub has shown repository license metadata for years, but the newer change is enforcement through dependency review, rulesets, and compliance checks that run before merge. That is a real shift from visibility to gatekeeping.&lt;/p&gt;

&lt;p&gt;A concrete example makes the change easier to see. Suppose a pull request upgrades a package and pulls in a license your enterprise policy forbids. Under the new workflow, GitHub evaluates that dependency change against the policy, annotates the pull request, and, in Active mode, blocks merging until the dependency is replaced, the policy is changed, or an exception is approved.&lt;/p&gt;

&lt;p&gt;If you only want the short version, the answer is yes: GitHub changed license handling in pull requests from display and review into enforced policy checks for dependency changes. The key words are rulesets, dependency graph, annotations, and merge blocking. Those are the pieces that actually changed the workflow.&lt;/p&gt;

&lt;p&gt;For teams adopting this, the first step is usually not policy writing. It is checking whether dependency graph data is enabled, whether the repositories are targeted by the right ruleset, and whether the team wants Evaluate mode first or Active mode right away. GitHub’s own setup flow recommends testing enforcement on a pull request that changes dependency manifests, then reviewing the annotations and unresolved violations before turning on stricter blocking.&lt;/p&gt;

&lt;p&gt;For readers who build on GitHub but do not administer an enterprise license policy, the practical takeaway is smaller. You may see annotations, blocked merges, or exception requests in pull requests, but those are signs of the enterprise policy layer at work. They are not a general change to how GitHub treats every open source pull request on the platform.&lt;/p&gt;

&lt;p&gt;If you want to compare this with your own workflow, DevConnect is a separate place to coordinate testing and shipping work, and its public materials can help with that context. The point here is still the same, though: on GitHub, license enforcement in pull requests is now policy-based and merge-aware, not just informational. &lt;a href="https://devconnectplatform.com?ref=devto" rel="noopener noreferrer"&gt;https://devconnectplatform.com?ref=devto&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Is this the same thing as dependency review
&lt;/h3&gt;

&lt;p&gt;No. GitHub’s newer license compliance feature builds on dependency data and pull request checks, but it is described as enterprise policy enforcement through rulesets. It compares dependency changes to policy and can block merges in Active mode, which is more explicit enforcement than a simple review comment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does GitHub check licenses in every pull request
&lt;/h3&gt;

&lt;p&gt;No. GitHub says the check runs when a pull request changes package manifests and evaluates dependency changes against policy. That means code-only changes without dependency manifest changes are not the same case, and repositories need the relevant dependency data and ruleset setup for enforcement to work.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can a blocked pull request still be merged
&lt;/h3&gt;

&lt;p&gt;Not while the Active ruleset requirement is failing. GitHub says unresolved noncompliant dependencies keep the pull request blocked until the dependency is fixed, the policy is updated, or an approved exception resolves the violation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Who can approve exceptions
&lt;/h3&gt;

&lt;p&gt;GitHub assigns that work to enterprise-level license policy managers. They review pending requests in enterprise security views and can approve package, license, or package-pattern exceptions at repository or enterprise scope.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is this feature available to every GitHub user
&lt;/h3&gt;

&lt;p&gt;No. GitHub documents it for GitHub Enterprise Cloud customers with GitHub Code Security or GitHub Advanced Security Code Security licenses, and it is in public preview. That makes it an enterprise feature with change risk, not a universal default.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently asked
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Is this the same thing as dependency review&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. GitHub’s newer license compliance feature builds on dependency data and pull request checks, but it is described as enterprise policy enforcement through rulesets. It compares dependency changes to policy and can block merges in Active mode, which is more explicit enforcement than a simple review comment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does GitHub check licenses in every pull request&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. GitHub says the check runs when a pull request changes package manifests and evaluates dependency changes against policy. That means code-only changes without dependency manifest changes are not the same case, and repositories need the relevant dependency data and ruleset setup for enforcement to work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can a blocked pull request still be merged&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not while the Active ruleset requirement is failing. GitHub says unresolved noncompliant dependencies keep the pull request blocked until the dependency is fixed, the policy is updated, or an approved exception resolves the violation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who can approve exceptions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;GitHub assigns that work to enterprise-level license policy managers. They review pending requests in enterprise security views and can approve package, license, or package-pattern exceptions at repository or enterprise scope.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is this feature available to every GitHub user&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. GitHub documents it for GitHub Enterprise Cloud customers with GitHub Code Security or GitHub Advanced Security Code Security licenses, and it is in public preview. That makes it an enterprise feature with change risk, not a universal default.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/code-security/concepts/supply-chain-security/open-source-license-compliance" rel="noopener noreferrer"&gt;About open source license compliance - GitHub Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/code-security/how-tos/secure-your-supply-chain/manage-your-dependency-security/configure-license-policies" rel="noopener noreferrer"&gt;Configuring open source license policies - GitHub Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.blog/changelog/2026-06-30-open-source-license-compliance-is-in-public-preview/" rel="noopener noreferrer"&gt;Open source license compliance is in public preview - GitHub Changelog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.blog/enterprise-software/governance-and-compliance/how-github-maintains-compliance-for-open-source-dependencies/" rel="noopener noreferrer"&gt;How GitHub maintains compliance for open source dependencies - The GitHub Blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.blog/news-insights/product-news/license-now-displayed-on-repository-overview/" rel="noopener noreferrer"&gt;License now displayed on repository overview - The GitHub Blog&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Originally published at &lt;a href="https://devconnectplatform.com/answers/did-github-change-how-open-source-licenses-are-enforced-in-p?ref=devto" rel="noopener noreferrer"&gt;devconnectplatform.com&lt;/a&gt;, where it is kept up to date.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>programming</category>
      <category>career</category>
      <category>discuss</category>
    </item>
    <item>
      <title>ColdFusion Stored Procedures vs Inline SQL: Performance, Security, and Maintainability</title>
      <dc:creator>Deepak Sir</dc:creator>
      <pubDate>Mon, 24 Aug 2026 06:07:48 +0000</pubDate>
      <link>https://dev.to/deepak_sir__/coldfusion-stored-procedures-vs-inline-sql-performance-security-and-maintainability-npe</link>
      <guid>https://dev.to/deepak_sir__/coldfusion-stored-procedures-vs-inline-sql-performance-security-and-maintainability-npe</guid>
      <description>&lt;p&gt;In ColdFusion you can run your database logic two ways — as inline SQL inside  / queryExecute(), or as stored procedures in the database called via  with  and  — and the honest answer to "which is better" is it depends on the query and your architecture, not a universal winner. Stored procedures traditionally win on three fronts: performance for complex, frequently-run queries (the database compiles and caches an execution plan the procedure reuses), security (you grant EXECUTE on the procedure without granting access to the underlying tables, and reduce the SQL-injection surface), and maintainability at scale (business logic centralized in one place, fixable without redeploying the app). Inline SQL wins on flexibility (change a query instantly, iterate fast), transparency (the SQL lives right next to your business logic where you can read it), and version control (it travels with your application code in Git). Crucially, the "stored procedures are always faster" claim is dated — for simple queries the difference is negligible or can even reverse, and both approaches are safe only if parameterized (cfqueryparam for inline, cfprocparam for procs). Most mature ColdFusion apps use both: stored procedures for complex, security-sensitive, or heavily-reused operations, and inline SQL for everything else. This guide compares them fairly across performance, security, and maintainability.&lt;br&gt;
&lt;strong&gt;&lt;a href="https://medium.com/@Coding-Algorithms/coldfusion-stored-procedures-vs-inline-sql-performance-security-and-maintainability-9d7282b6f12a?sharedUserId=Coding-Algorithms" rel="noopener noreferrer"&gt;Read More&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>sql</category>
      <category>security</category>
      <category>opensource</category>
    </item>
    <item>
      <title>AI Wrote the Code. You Still Own the Risk: 5 AI Product Engineering Companies I'd Shortlist in 2026</title>
      <dc:creator>Arjun</dc:creator>
      <pubDate>Mon, 24 Aug 2026 06:06:43 +0000</pubDate>
      <link>https://dev.to/arjun_07/ai-wrote-the-code-you-still-own-the-risk-5-ai-product-engineering-companies-id-shortlist-in-2026-a6c</link>
      <guid>https://dev.to/arjun_07/ai-wrote-the-code-you-still-own-the-risk-5-ai-product-engineering-companies-id-shortlist-in-2026-a6c</guid>
      <description>&lt;p&gt;Building an application with AI has become dramatically easier.&lt;/p&gt;

&lt;p&gt;Shipping one responsibly has not.&lt;/p&gt;

&lt;p&gt;A developer can now describe a feature, generate much of its implementation, connect an LLM API, deploy the application, and have something usable surprisingly quickly. That is genuinely valuable.&lt;/p&gt;

&lt;p&gt;But I think the AI development conversation has become too obsessed with how quickly software can be created.&lt;/p&gt;

&lt;p&gt;My position is the opposite: &lt;strong&gt;the more code AI generates, the more disciplined the engineering process around that code needs to become.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;AI does not remove engineering responsibility. It increases the amount of software, dependencies, data flows, and automated decisions a team may need to understand.&lt;/p&gt;

&lt;p&gt;That is why I would choose a specialized AI product engineering team over a generic app development company for any AI product expected to handle sensitive information, raise funding, pass enterprise procurement, or operate in a regulated industry.&lt;/p&gt;

&lt;p&gt;That is my bias, and I think founders should have the same one.&lt;/p&gt;

&lt;h2&gt;
  
  
  "AI Built It" Is Not a Risk Strategy
&lt;/h2&gt;

&lt;p&gt;One useful analysis of the problem is this discussion of &lt;a href="https://geekyants.com/en-us/blog/can-you-get-sued-for-an-ai-built-app-legal-risks-founders-should-know?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;legal risks surrounding AI-built applications&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The broader engineering point is more important than the headline.&lt;/p&gt;

&lt;p&gt;Using AI during development does not make the people and organizations deploying the software disappear from the accountability chain.&lt;/p&gt;

&lt;p&gt;If an application leaks customer information, uses software in violation of a license, produces harmful automated decisions, or makes claims that cannot be supported, saying that an AI coding assistant generated the implementation is unlikely to solve the underlying problem.&lt;/p&gt;

&lt;p&gt;The interesting question for developers is therefore not:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Did AI write this code?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can the engineering team explain where the code, data, models, dependencies, and decisions came from?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That distinction becomes increasingly important as AI moves from coding assistant to active participant across the software development lifecycle.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI-Generated Code Creates a Provenance Problem
&lt;/h2&gt;

&lt;p&gt;Traditional engineering already has dependency risk.&lt;/p&gt;

&lt;p&gt;AI adds another layer.&lt;/p&gt;

&lt;p&gt;An engineer normally knows whether a package came from npm, PyPI, Maven, GitHub, or an internal repository. There is usually a manifest, version, license, and dependency tree to inspect.&lt;/p&gt;

&lt;p&gt;AI-generated code can make provenance less obvious.&lt;/p&gt;

&lt;p&gt;A coding assistant might produce a function that looks perfectly ordinary. The developer may modify it and commit it without knowing whether similar code existed in its training data.&lt;/p&gt;

&lt;p&gt;That does &lt;strong&gt;not&lt;/strong&gt; mean every AI-generated snippet is automatically a copyright violation. It also does not mean that encountering copyleft code magically converts an entire proprietary application into open source. License obligations depend on the actual license, distribution model, copied material, and circumstances.&lt;/p&gt;

&lt;p&gt;But it does mean engineering teams need to stop treating generated code as inherently clean code.&lt;/p&gt;

&lt;p&gt;The U.S. Copyright Office has also maintained the importance of human authorship when considering copyright protection for AI-generated material. Human creative contribution can be protected, while merely prompting a system is not enough by itself.&lt;/p&gt;

&lt;p&gt;For software teams, the practical response should be boring engineering discipline: code review, dependency scanning, Software Bills of Materials where appropriate, license checks, source-control history, and documented human approval.&lt;/p&gt;

&lt;p&gt;Boring is good when lawyers arrive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Privacy Risk Is More Interesting Than Prompt Quality
&lt;/h2&gt;

&lt;p&gt;Developers spend enormous amounts of time improving prompts.&lt;/p&gt;

&lt;p&gt;I think many teams should spend more time drawing data-flow diagrams.&lt;/p&gt;

&lt;p&gt;Imagine an AI support application.&lt;/p&gt;

&lt;p&gt;A customer enters personal information. The application sends some of it to an orchestration service. That service retrieves account information. The resulting context goes to an external model API. Logs are stored by another provider. Observability data goes somewhere else.&lt;/p&gt;

&lt;p&gt;Suddenly, "the chatbot" is six systems.&lt;/p&gt;

&lt;p&gt;Engineering leadership should be able to identify what information each system receives, how long it keeps it, whether it is used for model training, who can access it, and what happens when a customer requests deletion.&lt;/p&gt;

&lt;p&gt;That is an architecture problem before it becomes a legal problem.&lt;/p&gt;

&lt;p&gt;NIST's Generative AI Profile similarly treats AI risk management as something that should operate across the AI lifecycle rather than as a final compliance exercise.&lt;/p&gt;

&lt;h2&gt;
  
  
  I Would Not Let AI-Generated Code Bypass the Normal SDLC
&lt;/h2&gt;

&lt;p&gt;There is a strange double standard emerging in software teams.&lt;/p&gt;

&lt;p&gt;A junior developer submits 500 lines of unfamiliar code, and everyone expects review.&lt;/p&gt;

&lt;p&gt;An AI assistant generates 500 lines in thirty seconds, and suddenly speed becomes the argument for merging faster.&lt;/p&gt;

&lt;p&gt;That makes no sense to me.&lt;/p&gt;

&lt;p&gt;AI-generated code deserves at least the same scrutiny as human-written code, and sometimes more.&lt;/p&gt;

&lt;p&gt;Security scanning should still happen. Tests should still happen. Threat modeling should still happen for sensitive features. Architecture decisions still need owners. High-impact AI outputs need human override paths. Models and third-party APIs need approval policies.&lt;/p&gt;

&lt;p&gt;The goal should not be slowing down AI-assisted development.&lt;/p&gt;

&lt;p&gt;The goal should be moving governance &lt;strong&gt;into&lt;/strong&gt; development.&lt;/p&gt;

&lt;p&gt;When that happens, a security or compliance review stops becoming an emergency two days before an enterprise launch.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Would I Look for in an AI Product Engineering Company?
&lt;/h2&gt;

&lt;p&gt;This is where my opinion becomes even more opinionated.&lt;/p&gt;

&lt;p&gt;I would &lt;strong&gt;not&lt;/strong&gt; prioritize the company that promises the fastest AI MVP.&lt;/p&gt;

&lt;p&gt;There are now hundreds of teams capable of creating a convincing LLM demonstration.&lt;/p&gt;

&lt;p&gt;I would prioritize the team that can explain how it takes that demonstration through architecture, model evaluation, security, privacy, QA, observability, deployment, governance, and ongoing maintenance.&lt;/p&gt;

&lt;p&gt;Using those criteria, these are five companies I would consider in 2026.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;GeekyAnts: My pick for focused AI product engineering&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For a company specifically trying to turn an AI application or AI-generated prototype into a production product, GeekyAnts would be my first shortlist candidate.&lt;/p&gt;

&lt;p&gt;The reason is relatively narrow. Its positioning sits closer to product engineering, AI engineering, modernization, backend development, QA, and production delivery than broad management consulting.&lt;/p&gt;

&lt;p&gt;Its recent discussion around AI-built application risk also shows attention to provenance, data handling, governance, security, and enterprise review rather than treating AI development purely as prompt engineering.&lt;/p&gt;

&lt;p&gt;I would not choose GeekyAnts because it can replace legal counsel. It cannot, and software engineering companies should not pretend otherwise.&lt;/p&gt;

&lt;p&gt;I would consider it when the core problem is &lt;strong&gt;engineering an AI product that legal and security teams can actually inspect&lt;/strong&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Thoughtworks: My pick for engineering rigor&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Thoughtworks would rank extremely highly for organizations where software architecture and engineering practices are the harder problem.&lt;/p&gt;

&lt;p&gt;Its recent work on moving generative AI beyond prototypes focuses heavily on integration, safety, industrialization, and structured AI-native engineering rather than "vibe coding."&lt;/p&gt;

&lt;p&gt;For complex platforms or companies with strong internal engineering organizations, that depth would make Thoughtworks particularly attractive.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;EPAM: My pick for large regulated enterprises&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;EPAM would move higher on my list as organizational complexity increases.&lt;/p&gt;

&lt;p&gt;Its AI engineering capabilities explicitly cover production AI platforms, governance, model monitoring, responsible AI, quality engineering, and large-scale software delivery.&lt;/p&gt;

&lt;p&gt;A startup might find that level of enterprise machinery unnecessary. A global financial, healthcare, or highly regulated organization may consider it exactly what it needs.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Globant: My pick for AI plus digital product experience&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Globant becomes interesting when AI is only one part of a much larger customer-facing digital product.&lt;/p&gt;

&lt;p&gt;Its enterprise AI work combines engineering, integrations, AI delivery, and responsible AI practices, which makes it relevant for organizations building AI into broader digital ecosystems rather than standalone experiments.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Accenture: My pick for governance-heavy transformations&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Accenture would not be my first choice for a lean founder trying to harden a focused AI MVP.&lt;/p&gt;

&lt;p&gt;For a multinational organization that needs technology delivery tied into cybersecurity, compliance, governance, organizational policy, and enterprise transformation, however, its scale becomes an advantage.&lt;/p&gt;

&lt;p&gt;Its responsible AI work clearly treats privacy, security, auditability, human oversight, and legal requirements as part of deploying AI applications.&lt;/p&gt;

&lt;p&gt;This is not an objective ranking of company size, revenue, or overall capability. It reflects one narrow question: &lt;strong&gt;who would I consider when the problem is getting AI software safely from prototype into serious production?&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Cheapest AI Build May Become the Most Expensive One
&lt;/h2&gt;

&lt;p&gt;This is ultimately why I take the specialist side.&lt;/p&gt;

&lt;p&gt;A generic development company may be perfectly capable of generating an AI MVP.&lt;/p&gt;

&lt;p&gt;That is not the bar anymore.&lt;/p&gt;

&lt;p&gt;The harder questions arrive later.&lt;/p&gt;

&lt;p&gt;Can someone identify every external model receiving customer information? Can the company prove which dependencies and licenses shipped? Are model outputs evaluated before releases? Can high-risk decisions be overridden? Are prompts and model versions traceable? Can an enterprise security team understand the architecture? Does someone actually own each AI feature after deployment?&lt;/p&gt;

&lt;p&gt;If those answers do not exist, a team does not have an AI governance problem.&lt;/p&gt;

&lt;p&gt;It has an engineering problem that has not failed publicly yet.&lt;/p&gt;

&lt;p&gt;My opinion is that &lt;strong&gt;AI product engineering is becoming its own specialization&lt;/strong&gt;, much like security engineering or platform engineering.&lt;/p&gt;

&lt;p&gt;The winners will not be the teams generating the most code.&lt;/p&gt;

&lt;p&gt;They will be the ones that can still explain, test, secure, and own that code after the novelty of generating it has disappeared.&lt;/p&gt;

&lt;p&gt;And that is why, for a serious AI product, I would choose specialist engineering over cheap AI development almost every time.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>security</category>
      <category>opensource</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Marker and Surya are Apache 2.0 — their model weights are not</title>
      <dc:creator>toolfreebie</dc:creator>
      <pubDate>Mon, 24 Aug 2026 06:02:22 +0000</pubDate>
      <link>https://dev.to/build996/marker-and-surya-are-apache-20-their-model-weights-are-not-28lo</link>
      <guid>https://dev.to/build996/marker-and-surya-are-apache-20-their-model-weights-are-not-28lo</guid>
      <description>&lt;p&gt;If you pick an OCR library by glancing at the license badge on its GitHub page, these two will catch you out.&lt;/p&gt;

&lt;p&gt;Marker and Surya (both from Datalab) show &lt;code&gt;Apache-2.0&lt;/code&gt; in GitHub's sidebar, and that is accurate — for the code. The model weights are under a separate licence: a modified AI Pubs Open Rail-M, free for research, personal use, and startups under $5M in funding or revenue. Past that line you need a commercial licence from Datalab. Both projects say so plainly in a "Commercial usage" section of their README; it just isn't what the badge reports, and the badge is what most roundups copy.&lt;/p&gt;

&lt;p&gt;The distinction matters because the badge is doing the opposite of its job here. Apache 2.0 on the repo tells you that you may use, modify and redistribute the &lt;em&gt;code&lt;/em&gt;. It says nothing about your right to run the &lt;em&gt;weights&lt;/em&gt; in a product — and without the weights the code does not do OCR.&lt;/p&gt;

&lt;p&gt;One thing worth flagging if you are reading older comparisons: Marker used to be GPL-3.0 with a $2M cap. It has since relicensed the code to Apache 2.0 and both projects now sit at $5M. So a post from six months ago can be wrong in your favour or against it, in either direction. Check the README and the LICENSE file, not a table someone else compiled.&lt;/p&gt;

&lt;p&gt;If you need something with no revenue test at all, Docling is MIT, and Tesseract, olmOCR, PaddleOCR and RapidOCR are all Apache 2.0 end to end.&lt;/p&gt;

&lt;p&gt;Fuller comparison of the OCR options, hosted and self-hosted: &lt;a href="https://toolfreebie.com/free-ocr-api-pdf/" rel="noopener noreferrer"&gt;https://toolfreebie.com/free-ocr-api-pdf/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>machinelearning</category>
      <category>python</category>
      <category>ocr</category>
    </item>
    <item>
      <title>I mapped India's public financial data endpoints so you don't have to</title>
      <dc:creator>Satwik Basu</dc:creator>
      <pubDate>Mon, 24 Aug 2026 05:57:50 +0000</pubDate>
      <link>https://dev.to/satwik001/i-mapped-indias-public-financial-data-endpoints-so-you-dont-have-to-1jdi</link>
      <guid>https://dev.to/satwik001/i-mapped-indias-public-financial-data-endpoints-so-you-dont-have-to-1jdi</guid>
      <description>&lt;p&gt;Indian financial market data can cost companies lakhs of rupees every year.&lt;/p&gt;

&lt;p&gt;But a lot of the underlying data is already publicly available.&lt;/p&gt;

&lt;p&gt;The expensive part isn't always the data itself. It's figuring out where it lives and how to reliably consume it.&lt;/p&gt;

&lt;p&gt;If you've ever tried building something around Indian financial data, you've probably encountered the same problems: undocumented endpoints, APIs with strange headers, inconsistent file formats, identifier changes, historical gaps, and datasets spread across different public sources.&lt;/p&gt;

&lt;p&gt;I've spent a lot of time digging through those problems.&lt;/p&gt;

&lt;p&gt;So instead of keeping the findings in a pile of scripts and notes, I mapped the endpoints I could find and open-sourced them.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's in the repository?
&lt;/h2&gt;

&lt;p&gt;The repository currently documents public endpoints covering several areas of Indian financial data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mutual fund NAV data
&lt;/h3&gt;

&lt;p&gt;Around &lt;strong&gt;14,000 mutual fund schemes&lt;/strong&gt; with more than &lt;strong&gt;18 years of NAV history&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;There are also parameterized APIs for retrieving historical NAV timelines.&lt;/p&gt;

&lt;h3&gt;
  
  
  Expense ratios
&lt;/h3&gt;

&lt;p&gt;Daily &lt;strong&gt;Total Expense Ratio (TER)&lt;/strong&gt; data, broken down across the available regulatory expense components.&lt;/p&gt;

&lt;h3&gt;
  
  
  NSE index data
&lt;/h3&gt;

&lt;p&gt;Historical valuation metrics including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PE&lt;/li&gt;
&lt;li&gt;PB&lt;/li&gt;
&lt;li&gt;Dividend yield&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The dataset covers &lt;strong&gt;140+ NSE indices&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;There's also historical &lt;strong&gt;Total Return Index (TRI)&lt;/strong&gt; data for Nifty indices.&lt;/p&gt;

&lt;h3&gt;
  
  
  Industry AUM
&lt;/h3&gt;

&lt;p&gt;Industry-wide mutual fund AUM statistics going back to &lt;strong&gt;2009&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Corporate shareholding
&lt;/h3&gt;

&lt;p&gt;Corporate shareholding data sourced from public &lt;strong&gt;iXBRL disclosures&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The goal isn't to build another financial-data product.&lt;/p&gt;

&lt;p&gt;It's to make the underlying discovery work easier for developers building things on top of public data.&lt;/p&gt;

&lt;h2&gt;
  
  
  The interesting part: the data has traps
&lt;/h2&gt;

&lt;p&gt;Finding an endpoint is only the beginning.&lt;/p&gt;

&lt;p&gt;While mapping these sources, I ran into several things that could quietly cause problems in production.&lt;/p&gt;

&lt;h3&gt;
  
  
  Historical discontinuities
&lt;/h3&gt;

&lt;p&gt;Some datasets have historical discontinuities around &lt;strong&gt;April 2019&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you're building a long-term time series, you can't blindly assume that the data behaves consistently across the entire history.&lt;/p&gt;

&lt;h3&gt;
  
  
  Files that lie about their format
&lt;/h3&gt;

&lt;p&gt;Some files claim to be one format while actually containing data in another.&lt;/p&gt;

&lt;p&gt;That can be particularly annoying when you're writing automated ingestion pipelines that trust file extensions or content types.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fund identifiers aren't always stable
&lt;/h3&gt;

&lt;p&gt;Mergers, rebranding and other changes can make fund identifier mappings surprisingly messy.&lt;/p&gt;

&lt;p&gt;If you're maintaining historical data, you need to account for those relationships rather than treating every identifier as permanently immutable.&lt;/p&gt;

&lt;h3&gt;
  
  
  The one-header problem
&lt;/h3&gt;

&lt;p&gt;Here's one of my favorite examples.&lt;/p&gt;

&lt;p&gt;There's a public corporate shareholding endpoint that appears to reject automated requests.&lt;/p&gt;

&lt;p&gt;You might assume there's authentication, some elaborate anti-bot mechanism, or another access restriction involved.&lt;/p&gt;

&lt;p&gt;In one case, the problem was simply the &lt;code&gt;Origin&lt;/code&gt; header.&lt;/p&gt;

&lt;p&gt;Remove it and the request works.&lt;/p&gt;

&lt;p&gt;That's it.&lt;/p&gt;

&lt;p&gt;One HTTP header was the difference between "this endpoint doesn't work" and getting the data immediately.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I open-sourced this
&lt;/h2&gt;

&lt;p&gt;I've had to spend hours figuring out things that probably shouldn't take hours to figure out.&lt;/p&gt;

&lt;p&gt;And I know I'm not the only developer doing it.&lt;/p&gt;

&lt;p&gt;Someone building a portfolio tracker shouldn't have to spend days reverse-engineering network requests just to discover where historical data comes from.&lt;/p&gt;

&lt;p&gt;Someone building a quantitative research tool shouldn't have to rediscover the same identifier mappings.&lt;/p&gt;

&lt;p&gt;Someone building a fintech prototype shouldn't have to start from zero because the documentation around a public endpoint is scattered or nonexistent.&lt;/p&gt;

&lt;p&gt;So I decided to put the findings in one place.&lt;/p&gt;

&lt;p&gt;The repository is &lt;strong&gt;MIT licensed&lt;/strong&gt;, so you can use it as a starting point for projects involving:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Indian fintech&lt;/li&gt;
&lt;li&gt;Wealth management&lt;/li&gt;
&lt;li&gt;Quantitative research&lt;/li&gt;
&lt;li&gt;Portfolio tracking&lt;/li&gt;
&lt;li&gt;Market analytics&lt;/li&gt;
&lt;li&gt;Financial data pipelines&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are probably still gaps.&lt;/p&gt;

&lt;p&gt;That's intentional.&lt;/p&gt;

&lt;p&gt;I mapped what I could find, documented the behavior I encountered, and would rather have other developers extend it than keep trying to maintain a private collection of scripts.&lt;/p&gt;

&lt;h2&gt;
  
  
  One less thing to reverse-engineer
&lt;/h2&gt;

&lt;p&gt;The data was public.&lt;/p&gt;

&lt;p&gt;The documentation wasn't.&lt;/p&gt;

&lt;p&gt;That's the problem I'm trying to solve with this repository.&lt;/p&gt;

&lt;p&gt;If you're building something around Indian financial data, hopefully this saves you a few days of digging through network requests and figuring out why an otherwise perfectly reasonable API request gets rejected because of one header.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Repository:&lt;/strong&gt; &lt;a href="https://github.com/satwikbasu" rel="noopener noreferrer"&gt;https://github.com/satwikbasu&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you know of other undocumented Indian market-data endpoints, PRs and contributions are very welcome.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>api</category>
      <category>python</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Your license scanner is answering the wrong question</title>
      <dc:creator>Ryosuke Aoki</dc:creator>
      <pubDate>Mon, 24 Aug 2026 05:56:30 +0000</pubDate>
      <link>https://dev.to/ryosuke_aoki_2266a6aa25dc/your-license-scanner-is-answering-the-wrong-question-j0c</link>
      <guid>https://dev.to/ryosuke_aoki_2266a6aa25dc/your-license-scanner-is-answering-the-wrong-question-j0c</guid>
      <description>&lt;p&gt;Run a license scanner over a typical Node or Python project and you get a table:&lt;br&gt;
package, license, risk level. &lt;code&gt;GPL-3.0&lt;/code&gt; comes back red. &lt;code&gt;MIT&lt;/code&gt; comes back green.&lt;br&gt;
&lt;code&gt;MPL-2.0&lt;/code&gt; comes back yellow, probably.&lt;/p&gt;

&lt;p&gt;That table is answering a question nobody asked, which is &lt;em&gt;"is this license&lt;br&gt;
scary?"&lt;/em&gt; The question you actually have is &lt;em&gt;"does this obligate me to do&lt;br&gt;
something?"&lt;/em&gt; — and for a large fraction of licenses, the honest answer is: it&lt;br&gt;
depends on facts the scanner never asked you about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Copyleft obligations attach to events, not to code
&lt;/h2&gt;

&lt;p&gt;Read GPL-3.0 looking for the trigger and you find it in section 5: the&lt;br&gt;
requirement to license the whole work under the same terms and make&lt;br&gt;
corresponding source available applies when you &lt;strong&gt;convey&lt;/strong&gt; the work. Conveying&lt;br&gt;
is distribution. If you never distribute, the obligation never fires.&lt;/p&gt;

&lt;p&gt;So consider a hosted SaaS product with a GPL-3.0 library in &lt;code&gt;node_modules&lt;/code&gt;,&lt;br&gt;
running on your own servers, with users reaching it over HTTPS.&lt;/p&gt;

&lt;p&gt;You have not distributed anything. Nobody received a copy. The obligation does&lt;br&gt;
not arise.&lt;/p&gt;

&lt;p&gt;Your scanner said red.&lt;/p&gt;

&lt;p&gt;Now consider the same library, same version, same lockfile, in a desktop app you&lt;br&gt;
ship to customers. Distribution. The obligation fires, and it fires on &lt;em&gt;the&lt;br&gt;
whole work&lt;/em&gt; — your proprietary code included.&lt;/p&gt;

&lt;p&gt;Your scanner said red. Same red. Same shade of red.&lt;/p&gt;

&lt;p&gt;One of those two answers was useless. The scanner had no way to tell them apart,&lt;br&gt;
because it never asked how the software reaches its users.&lt;/p&gt;

&lt;h2&gt;
  
  
  The AGPL exists precisely because that gap is real
&lt;/h2&gt;

&lt;p&gt;The Free Software Foundation noticed the SaaS hole and wrote a license to close&lt;br&gt;
it. AGPL-3.0 section 13 adds an obligation the GPL does not have: if users&lt;br&gt;
interact with a modified version &lt;strong&gt;over a network&lt;/strong&gt;, you must offer them the&lt;br&gt;
corresponding source of the whole work.&lt;/p&gt;

&lt;p&gt;That single clause is the entire practical difference for a hosted service:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Hosted SaaS&lt;/th&gt;
&lt;th&gt;Distributed binary&lt;/th&gt;
&lt;th&gt;Internal only&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GPL-3.0&lt;/td&gt;
&lt;td&gt;no obligation&lt;/td&gt;
&lt;td&gt;obligation fires&lt;/td&gt;
&lt;td&gt;no obligation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AGPL-3.0&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;obligation fires&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;obligation fires&lt;/td&gt;
&lt;td&gt;no obligation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two licenses that most tools file under the same "strong copyleft, high risk"&lt;br&gt;
heading, producing opposite answers for the deployment model most companies&lt;br&gt;
actually use.&lt;/p&gt;

&lt;p&gt;And note the third column. For internal-only software — an internal dashboard,&lt;br&gt;
a build tool, something that never leaves the company — neither license&lt;br&gt;
obligates you to disclose anything. Not because of a loophole, but because&lt;br&gt;
neither distribution nor network interaction with outside users ever happens.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dev dependencies are a different question entirely
&lt;/h2&gt;

&lt;p&gt;This one causes more unnecessary panic than anything else.&lt;/p&gt;

&lt;p&gt;If a GPL-3.0 package appears in your lockfile as a dev dependency — a test&lt;br&gt;
runner, a linter, a bundler — it is not part of the artifact you ship. No&lt;br&gt;
distribution of &lt;em&gt;that package&lt;/em&gt; occurs. No obligation arises.&lt;/p&gt;

&lt;p&gt;The caveat worth stating out loud: tools that &lt;strong&gt;emit code into your output&lt;/strong&gt; are&lt;br&gt;
a separate case. A code generator whose templates land in your shipped source is&lt;br&gt;
not the same as a linter that only reads your source. Worth checking&lt;br&gt;
individually rather than assuming.&lt;/p&gt;

&lt;p&gt;Most scanners flatten this too. &lt;code&gt;dependencies&lt;/code&gt; and &lt;code&gt;devDependencies&lt;/code&gt; are right&lt;br&gt;
there in the manifest, distinguished by the ecosystem itself, and the report&lt;br&gt;
still shows one risk column.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not every license works this way
&lt;/h2&gt;

&lt;p&gt;It is worth being precise about which licenses this distinction actually&lt;br&gt;
changes, because "it depends" is not useful if it applies to everything.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It changes the answer for:&lt;/strong&gt; GPL, AGPL, LGPL, and the source-available&lt;br&gt;
licenses like SSPL and BUSL — anything whose trigger is a distribution or&lt;br&gt;
network-interaction event.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It does not change the answer for:&lt;/strong&gt; MIT, Apache-2.0, BSD. Permissive licenses&lt;br&gt;
ask for attribution and not much else, in every model. Apache-2.0 adds a patent&lt;br&gt;
grant and a NOTICE requirement, which are obligations, but they do not vary by&lt;br&gt;
how you ship.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MPL-2.0 is the interesting middle.&lt;/strong&gt; Its copyleft is per &lt;em&gt;file&lt;/em&gt;, not per&lt;br&gt;
project. Files it covers stay under it and their modifications must be&lt;br&gt;
published; your own files carry whatever terms you choose. It treats static and&lt;br&gt;
dynamic linking alike. So the shipping model barely matters — but for a reason&lt;br&gt;
that is the opposite of the permissive case: the obligation is real, it is just&lt;br&gt;
scoped narrowly enough that it does not reach your code.&lt;/p&gt;

&lt;p&gt;Three genuinely different mechanisms. One risk column cannot represent them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Linkage is the second axis
&lt;/h2&gt;

&lt;p&gt;For compiled languages there is a further fact the manifest does not tell you.&lt;/p&gt;

&lt;p&gt;LGPL's whole design is that you may use the library in a proprietary work&lt;br&gt;
provided the user can replace it — which dynamic linking gives you almost for&lt;br&gt;
free, and static linking does not. In Go and Rust, static linking is the&lt;br&gt;
default. So the same LGPL dependency has a materially different answer in a Rust&lt;br&gt;
binary than in a Node application, and nothing in &lt;code&gt;Cargo.lock&lt;/code&gt; says so.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to do about it
&lt;/h2&gt;

&lt;p&gt;Nothing exotic. When you look at a license question, fix three facts first:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;How does this reach users?&lt;/strong&gt; Hosted, distributed binary, delivered to a
customer's environment, internal only, or published as a library.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Is it in the shipped artifact?&lt;/strong&gt; Runtime or dev-only.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How is it linked?&lt;/strong&gt; Static or dynamic — only matters for compiled
languages and only for a few licenses.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With those three fixed, most "it depends" answers collapse into one answer. Not&lt;br&gt;
a risk score — an actual yes or no, with the clause that produced it.&lt;/p&gt;

&lt;p&gt;That is also the honest reason a scanner cannot do this for you out of the box:&lt;br&gt;
two of those three facts are not in your repository. They are facts about your&lt;br&gt;
business.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I got annoyed enough at re-deriving this by hand that I built a small free tool&lt;br&gt;
that takes the shipping model as an input and gives the per-model answer with&lt;br&gt;
the clause behind it: &lt;a href="https://licenseguard.tenchorooms.com" rel="noopener noreferrer"&gt;https://licenseguard.tenchorooms.com&lt;/a&gt;. It also runs as an&lt;br&gt;
MCP server if you want your coding agent to stop guessing at this. Source is&lt;br&gt;
Apache-2.0 on GitHub.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Not legal advice. It tells you which clause is implicated and why, which is the&lt;br&gt;
part that is mechanical. Whether it applies to your situation is not.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>programming</category>
      <category>legal</category>
      <category>devops</category>
    </item>
    <item>
      <title>How SmartKey Keeps Two Alphabets Alive Until Context Decides</title>
      <dc:creator>Ruslan Manov</dc:creator>
      <pubDate>Mon, 24 Aug 2026 05:55:15 +0000</pubDate>
      <link>https://dev.to/ruslan_manov/how-smartkey-keeps-two-alphabets-alive-until-context-decides-461k</link>
      <guid>https://dev.to/ruslan_manov/how-smartkey-keeps-two-alphabets-alive-until-context-decides-461k</guid>
      <description>&lt;p&gt;The input event does not arrive with a language tag.&lt;/p&gt;

&lt;p&gt;Press the same two physical keys on a Bulgarian phonetic keyboard and one interpretation is &lt;code&gt;li&lt;/code&gt;; the other is &lt;code&gt;ли&lt;/code&gt;. Both are plausible prefixes. One can be the beginning of &lt;em&gt;like&lt;/em&gt;. The other can already be a complete Bulgarian word.&lt;/p&gt;

&lt;p&gt;Most desktop input systems avoid this ambiguity by asking the user to maintain a global mode: English now, Bulgarian later. The engineering is simple. The human cost appears when the mode and the thought diverge. A forgotten toggle turns a sentence into cleanup work.&lt;/p&gt;

&lt;p&gt;SmartKey explores a different contract: keep both alphabets alive long enough for evidence to decide.&lt;/p&gt;

&lt;p&gt;Its North Star is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Write the thought, not the keyboard layout.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This article is the technical companion to the project's narrative overview. It focuses on what an input engine designer can learn from the architecture, its current evidence, and the failures that refuse to fit under one convenient label.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Start before autocorrect
&lt;/h2&gt;

&lt;p&gt;Autocorrect begins with committed text and asks whether another string was intended. A dual-alphabet input engine has an earlier problem: what characters should the physical keys become in the first place?&lt;/p&gt;

&lt;p&gt;SmartKey maintains two candidate readings for the current word. Conceptually, the loop looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for each eligible physical key:
    extend the English candidate
    extend the Bulgarian candidate
    score both using available local evidence

    if the winner changes before the decision is locked:
        update the visible composing prefix

    if the evidence crosses a lock boundary:
        lock the current winner for further scoring
        keep the word in preedit until the boundary
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is pseudocode, not a copy of the Rust implementation. The useful design idea is delayed commitment. The engine can expose a current best answer in composing preedit without pretending that early evidence is final.&lt;/p&gt;

&lt;p&gt;That distinction matters because the shape of evidence changes during a word. At the first character, context may be more informative than corpus frequency. After several characters, a prefix can become distinctive. At a delimiter, the token is no longer merely a prefix; exact-word and phrase evidence become available.&lt;/p&gt;

&lt;p&gt;One scoring rule should not be assumed optimal at all three moments.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Prefix evidence is not word evidence
&lt;/h2&gt;

&lt;p&gt;The smallest reproducible example is &lt;code&gt;li&lt;/code&gt; versus &lt;code&gt;ли&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In the audited corpus snapshot behind this draft, the strongest English completion for &lt;code&gt;li…&lt;/code&gt; was represented about 2.57 million times. The strongest Bulgarian completion for &lt;code&gt;ли…&lt;/code&gt; was close, at about 2.51 million. A prefix-based contest is therefore nearly balanced and can tip toward English.&lt;/p&gt;

&lt;p&gt;But at the exact-word boundary, the evidence is radically different: standalone Bulgarian &lt;code&gt;ли&lt;/code&gt; appeared about 2.51 million times, while standalone English &lt;code&gt;li&lt;/code&gt; appeared about 18 thousand times.&lt;/p&gt;

&lt;p&gt;The numbers are corpus-specific and rounded. Their value is not the apparent precision. Their value is the diagnostic question they expose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;During the token: “Which candidate has the strongest continuation?”&lt;/li&gt;
&lt;li&gt;At the delimiter: “Which candidate is the word the user just completed?”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the engine keeps asking the first question after Space arrives, it is solving the wrong problem correctly.&lt;/p&gt;

&lt;p&gt;This suggests a general rule for predictive interfaces: boundaries are semantic events. A delimiter, submit action, focus change, or explicit acceptance can reveal evidence that did not exist one event earlier. Test boundary behavior separately instead of treating it as the last iteration of the same loop.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Context is an input contract, not application telepathy
&lt;/h2&gt;

&lt;p&gt;It is tempting to summarize context handling as “the keyboard knows it is in a terminal.” SmartKey does not make that claim.&lt;/p&gt;

&lt;p&gt;The engine can use three bounded signals:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;surrounding text that the client exposes;&lt;/li&gt;
&lt;li&gt;the &lt;code&gt;ContentType&lt;/code&gt; the client declares;&lt;/li&gt;
&lt;li&gt;an inferred typing regime derived from available input evidence.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the FastCoding regime, technical vocabulary can influence prediction. It is ranking evidence, not a guarantee that every identifier or command will remain untouched.&lt;/p&gt;

&lt;p&gt;Sensitive fields have the same contractual boundary. SmartKey bypasses fields whose clients correctly publish a sensitive &lt;code&gt;ContentType&lt;/code&gt;. It cannot promise a universal password shield when a client fails to declare that property.&lt;/p&gt;

&lt;p&gt;This is an important architectural habit: name the source of context. “The application tells me X” and “I inferred Y from text” have different failure modes, security properties, and test fixtures.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Acceptance is a state transition
&lt;/h2&gt;

&lt;p&gt;A visible completion creates another decision boundary. SmartKey supports deliberate acceptance paths such as Tab and Right Arrow, with Escape available to reject.&lt;/p&gt;

&lt;p&gt;Space is attractive because it is already the natural end-of-word gesture. It is also dangerous. An input method may have to replace a partial token, commit a completion, preserve its alphabet, and deliver exactly one delimiter without leaking an intermediate state.&lt;/p&gt;

&lt;p&gt;The Space-accept path is therefore still experimental. Its feature flag is &lt;strong&gt;off&lt;/strong&gt;, and a newly discovered Unicode-eligibility issue is a release blocker. It is not a shipped capability in this article.&lt;/p&gt;

&lt;p&gt;The design lesson is broader than this feature: never model acceptance as a convenient key binding. Model it as a transaction with eligibility, commit, cancellation, and fallback semantics. If eligibility fails, Space must remain ordinary Space.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Local prediction still uses a model
&lt;/h2&gt;

&lt;p&gt;SmartKey keeps corpus scoring, contextual ranking, and personal adaptation on the machine. There is no LLM or remote model in the prediction loop.&lt;/p&gt;

&lt;p&gt;That wording is deliberate. “No model” would be false: ranking candidates is a model, even when the implementation is compact and inspectable. “No data” would also be misleading: local corpus and personal adaptation are data.&lt;/p&gt;

&lt;p&gt;Feedback needs the same precision. Accepted candidates can reinforce useful behavior. Repeated rejections can suppress a suggestion. If an accepted completion is followed by Backspace within 500 milliseconds, the event is recorded as negative feedback. The system does not need to label the user's emotion; it needs a bounded observation that a test can reproduce.&lt;/p&gt;

&lt;p&gt;For input software, local processing is not only a privacy feature. It also makes behavior easier to replay against a fixed corpus and exact revision.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Debug the decision without logging the sentence
&lt;/h2&gt;

&lt;p&gt;An input engine can be wrong at every keystroke. Plaintext logs would make diagnosis easy and create an unacceptable record of what the user typed.&lt;/p&gt;

&lt;p&gt;SmartKey's compromise is a structural per-keystroke receipt without plaintext. In structural mode, it records the input/script class, consume-or-forward verdict, dual-buffer and lock/hypothesis state, action name, payload or commit length, and—on commits—the typed and committed script classes.&lt;/p&gt;

&lt;p&gt;These fields are enough to inspect state transitions and dispatched action kinds without saving plaintext. They do not by themselves reveal candidate text or corpus support.&lt;/p&gt;

&lt;p&gt;At the combined revision behind this draft, the recorded verification gate passed 496 core tests, focused suites of 9, 5, and 20 cases, and seven native scenarios. Those tests describe one revision; they are not an accuracy measurement and do not erase the Unicode blocker in the experimental Space path.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. One symptom, three failure lanes
&lt;/h2&gt;

&lt;p&gt;In one diagnostic session, nine tokens in a roughly 45-word Bulgarian instruction surfaced in the wrong form. That is one diagnostic session, not a benchmark or an accuracy percentage.&lt;/p&gt;

&lt;p&gt;Two isolated examples teach different lessons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;no&lt;/code&gt;, intended as Bulgarian &lt;code&gt;но&lt;/code&gt;, reaches a delimiter while the engine still has a short-word ambiguity.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;statiq&lt;/code&gt;, intended as &lt;code&gt;статия&lt;/code&gt;, can be pulled toward Latin by strong &lt;code&gt;stat…&lt;/code&gt; prefix evidence before the Bulgarian word is complete.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Other observations involve loanwords, product names, abbreviations, out-of-vocabulary forms, punctuation, or ordinary typos. A surface string cannot prove which mechanism produced it. That requires the receipt and an exact replay.&lt;/p&gt;

&lt;p&gt;The next design work should therefore be split rather than hidden inside a mega-fix.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lane A — short words at the delimiter
&lt;/h3&gt;

&lt;p&gt;For ambiguous two- and three-character tokens, evaluate exact-word frequency, language prior, and phrase context when the delimiter arrives.&lt;/p&gt;

&lt;p&gt;RED tests should include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bulgarian short words after Bulgarian context;&lt;/li&gt;
&lt;li&gt;genuine English short words after English context;&lt;/li&gt;
&lt;li&gt;a language switch immediately before the token;&lt;/li&gt;
&lt;li&gt;punctuation and end-of-input as boundaries, not only Space.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Lane B — premature prefix lock and unsupported inheritance
&lt;/h3&gt;

&lt;p&gt;Test when a strong completion prefix can lock the wrong alphabet before the intended word has enough evidence. Separately test the case in which the nominal winner has zero support: it should not inherit a previous choice merely because a state variable already has a value.&lt;/p&gt;

&lt;p&gt;The exact fallback policy still needs evidence. The important step is to make “no support” an explicit state rather than silently treating it as confidence.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lane C — OOV, brands, abbreviations, and typos
&lt;/h3&gt;

&lt;p&gt;Loanwords and brand names cross the boundary between preservation and correction. A typo can make both corpus candidates unsupported. Punctuation can belong inside a technical token rather than terminate it.&lt;/p&gt;

&lt;p&gt;These cases need their own fixtures and success criteria. Solving Lane A must not be advertised as solving Lane C.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. What to take into another input engine
&lt;/h2&gt;

&lt;p&gt;SmartKey's validated integration here is Linux with IBus, Bulgarian and English, in the author's own daily use. It is not a Windows or macOS delivery claim, a multi-user field study, or evidence of perfect language selection.&lt;/p&gt;

&lt;p&gt;The reusable engineering principles are more important than the platform boundary:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Preserve competing interpretations until an irreversible decision is justified.&lt;/li&gt;
&lt;li&gt;Re-evaluate at semantic boundaries; a complete word is not merely a longer prefix.&lt;/li&gt;
&lt;li&gt;Distinguish declared context from inferred context.&lt;/li&gt;
&lt;li&gt;Treat completion acceptance as a transaction.&lt;/li&gt;
&lt;li&gt;Collect falsifiable structural evidence without storing plaintext.&lt;/li&gt;
&lt;li&gt;Split failures by mechanism before designing the fix.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A predictive system earns trust when its behavior is not only fast or often correct, but bounded, reversible, and explainable when wrong.&lt;/p&gt;

&lt;p&gt;The SmartKey repository is here: &lt;a href="https://github.com/RMANOV/smartkey" rel="noopener noreferrer"&gt;https://github.com/RMANOV/smartkey&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Canonical project story: &lt;a href="https://www.linkedin.com/pulse/fractured-console-two-alphabets-one-stream-thought-ruslan-manov-m3jvf/" rel="noopener noreferrer"&gt;https://www.linkedin.com/pulse/fractured-console-two-alphabets-one-stream-thought-ruslan-manov-m3jvf/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bring a reproducible boundary case. For this kind of engine, the most valuable input is the word that forces the scoring model to reveal what question it was really asking.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>linux</category>
      <category>programming</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Building an Open-Source, Zero-Knowledge DocSend Alternative with React 19 and Supabase</title>
      <dc:creator>Roushan kumar</dc:creator>
      <pubDate>Mon, 24 Aug 2026 05:45:47 +0000</pubDate>
      <link>https://dev.to/roushan71262/building-an-open-source-zero-knowledge-docsend-alternative-with-react-19-and-supabase-3oap</link>
      <guid>https://dev.to/roushan71262/building-an-open-source-zero-knowledge-docsend-alternative-with-react-19-and-supabase-3oap</guid>
      <description>&lt;h1&gt;
  
  
  Why We Built DocTransfer
&lt;/h1&gt;

&lt;p&gt;Sharing sensitive documents like pitch decks, financial reports, or legal contracts shouldn't require paying $250+/month for platforms that store your unencrypted files on their servers.&lt;/p&gt;

&lt;p&gt;We built &lt;strong&gt;&lt;a href="https://doctransfer.app" rel="noopener noreferrer"&gt;DocTransfer&lt;/a&gt;&lt;/strong&gt; (and open-sourced it on &lt;a href="https://github.com/simplegithubs/DocTransfer3949" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;) as a privacy-first, client-side encrypted document sharing and Virtual Data Room (VDR) platform.&lt;/p&gt;




&lt;h2&gt;
  
  
  Zero-Knowledge Cryptography Architecture
&lt;/h2&gt;

&lt;p&gt;Most document-sharing services encrypt files &lt;em&gt;at rest&lt;/em&gt; on their cloud storage. That means their backend servers - and anyone with access to them - can view your raw documents.&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;DocTransfer&lt;/strong&gt;, encryption happens entirely on the client before the payload leaves your browser:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Client-Side OpenPGP &amp;amp; AES-256-GCM&lt;/strong&gt;: Files are encrypted in the browser using the WebCrypto API and OpenPGP.js.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero-Knowledge Key Handling&lt;/strong&gt;: Encryption keys are kept in URL hash fragments (&lt;code&gt;#key=...&lt;/code&gt;), which are never sent to our servers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic Forensic Watermarking&lt;/strong&gt;: Recipient email overlays are rendered dynamically on the canvas layer, preventing unauthorized screenshots and distribution.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Tech Stack &amp;amp; Key Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Frontend&lt;/strong&gt;: React 19, TypeScript, Vite, Framer Motion&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database &amp;amp; Auth&lt;/strong&gt;: Supabase (PostgreSQL with strict Row-Level Security, Edge Functions, Storage)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Document Processing&lt;/strong&gt;: &lt;code&gt;pdf-lib&lt;/code&gt;, &lt;code&gt;react-pdf&lt;/code&gt;, &lt;code&gt;pdfjs-dist&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security &amp;amp; Signatures&lt;/strong&gt;: OpenPGP.js, SimpleWebAuthn (Biometric sign-in), Digital Certificate generation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analytics&lt;/strong&gt;: Real-time page-by-page engagement heatmaps &amp;amp; viewer telemetry&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Try It &amp;amp; Contribute
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Live App&lt;/strong&gt;: &lt;a href="https://doctransfer.app" rel="noopener noreferrer"&gt;doctransfer.app&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Repository&lt;/strong&gt;: &lt;a href="https://github.com/simplegithubs/DocTransfer3949" rel="noopener noreferrer"&gt;github.com/simplegithubs/DocTransfer3949&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We would love to get your feedback on the client-side encryption flow, PDF rendering optimizations, and general user experience!&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>showdev</category>
      <category>webdev</category>
      <category>security</category>
    </item>
    <item>
      <title>Self-Hosted Customer Support &amp; Helpdesks in 2026: Chatwoot vs FreeScout vs Helpy</title>
      <dc:creator>Elder Fernandes</dc:creator>
      <pubDate>Mon, 24 Aug 2026 05:45:34 +0000</pubDate>
      <link>https://dev.to/enfernandes/self-hosted-customer-support-helpdesks-in-2026-chatwoot-vs-freescout-vs-helpy-1d8b</link>
      <guid>https://dev.to/enfernandes/self-hosted-customer-support-helpdesks-in-2026-chatwoot-vs-freescout-vs-helpy-1d8b</guid>
      <description>&lt;h1&gt;
  
  
  Self-Hosted Customer Support &amp;amp; Helpdesks in 2026: Chatwoot vs FreeScout vs Helpy
&lt;/h1&gt;

&lt;p&gt;Delivering exceptional customer support is essential for growth, but commercial helpdesk platforms enforce punitive pricing models:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Per-Agent Seat Taxes:&lt;/strong&gt; Intercom, Zendesk, and Front charge $49 to $119+ per agent per month. As your support and engineering teams grow, licensing costs quickly spiral into tens of thousands of dollars annually.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add-On Paywalls:&lt;/strong&gt; Essential capabilities like WhatsApp integration, SMS channels, unlimited email history, and custom webhooks are locked behind enterprise tiers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customer Data Privacy:&lt;/strong&gt; Confidential customer conversations, billing inquiries, and personal data are held on third-party multi-tenant servers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Self-hosting an open-source support helpdesk gives your team &lt;strong&gt;unlimited agent seats, unified omnichannel inboxes (Live Chat, WhatsApp, Email, Telegram, Social), full webhook customization, and complete data ownership on your own VPS&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this guide, we evaluate the top three self-hosted support and ticketing platforms in 2026: &lt;strong&gt;Chatwoot&lt;/strong&gt;, &lt;strong&gt;FreeScout&lt;/strong&gt;, and &lt;strong&gt;Helpy&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Landscape: Comparative Breakdown
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature / Capability&lt;/th&gt;
&lt;th&gt;Chatwoot&lt;/th&gt;
&lt;th&gt;FreeScout&lt;/th&gt;
&lt;th&gt;Helpy&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Core Paradigm&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Modern Omnichannel Live Chat + Shared Inbox&lt;/td&gt;
&lt;td&gt;Clean Shared Email Inbox (Help Scout Alternative)&lt;/td&gt;
&lt;td&gt;Traditional Support Ticketing &amp;amp; Knowledge Base&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Technology Stack&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Ruby on Rails, Vue.js, PostgreSQL, Redis&lt;/td&gt;
&lt;td&gt;PHP (Laravel), MySQL/PostgreSQL, Vue&lt;/td&gt;
&lt;td&gt;Ruby on Rails, PostgreSQL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Supported Channels&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Web Live Chat, Email, WhatsApp, Telegram, Facebook, SMS&lt;/td&gt;
&lt;td&gt;Email Inboxes, Webhooks, Community Modules&lt;/td&gt;
&lt;td&gt;Email Ticketing, Public/Private Help Center&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Bot &amp;amp; AI Integrations&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Native Webhooks, Rasa, Dialogflow, OpenAI&lt;/td&gt;
&lt;td&gt;Modules available for automation &amp;amp; canned replies&lt;/td&gt;
&lt;td&gt;Automated workflows &amp;amp; AI taggers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Mobile Applications&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Official iOS &amp;amp; Android Apps&lt;/td&gt;
&lt;td&gt;Mobile Web / PWA / Community Apps&lt;/td&gt;
&lt;td&gt;Mobile responsive web UI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Hardware Overhead&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Moderate (2 vCPU, 4GB RAM)&lt;/td&gt;
&lt;td&gt;Ultra-Lightweight (1 vCPU, 1GB RAM)&lt;/td&gt;
&lt;td&gt;Lightweight (1-2 vCPU, 2GB RAM)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best Used For&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Real-time website chat, omnichannel SaaS support&lt;/td&gt;
&lt;td&gt;Shared team email management, agency ticketing&lt;/td&gt;
&lt;td&gt;Classic IT helpdesks and knowledge base portals&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Explore full feature comparisons and alternative tools at: &lt;a href="https://selfhoststack-8z4.pages.dev/alternatives/zendesk" rel="noopener noreferrer"&gt;SelfHostStack Zendesk Alternatives&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Chatwoot: The Modern Intercom &amp;amp; Crisp Alternative
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Chatwoot&lt;/strong&gt; is an open-source, omnichannel customer engagement suite. It unifies live website chat widgets, email support, WhatsApp business numbers, and social channels into a single real-time collaborative dashboard.&lt;/p&gt;

&lt;h3&gt;
  
  
  Standout Capabilities
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Embeddable Live Widget:&lt;/strong&gt; Customizable JavaScript widget with automated greetings, offline forms, and pre-chat surveys.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-Brand &amp;amp; Multi-Team Routing:&lt;/strong&gt; Route inquiries by department (Sales, Billing, Technical) with automated assignment rules.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rich Mobile Ecosystem:&lt;/strong&gt; Official native apps for iOS and Android allowing team members to resolve customer queries on the go.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Production Chatwoot Docker Compose Architecture
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.8"&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;chatwoot_web&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;chatwoot/chatwoot:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;chatwoot_web&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;redis&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;NODE_ENV=production&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;RAILS_ENV=production&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;INSTALLATION_ENV=docker&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SECRET_KEY_BASE=${SECRET_KEY_BASE}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;FRONTEND_URL=https://support.yourdomain.com&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_HOST=postgres&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_DATABASE=chatwoot_production&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_USERNAME=chatwoot&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_PASSWORD=${POSTGRES_PASSWORD}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;REDIS_URL=redis://redis:6379&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;MAILER_SENDER_EMAIL=support@yourdomain.com&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SMTP_ADDRESS=smtp.resend.com&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SMTP_PORT=587&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SMTP_USERNAME=resend&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SMTP_PASSWORD=${SMTP_PASSWORD}&lt;/span&gt;
    &lt;span class="na"&gt;entrypoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker/entrypoints/rails.sh&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;bundle'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;exec'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;rails'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;-p'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3000'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;-b'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;0.0.0.0'&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;127.0.0.1:3000:3000"&lt;/span&gt;

  &lt;span class="na"&gt;chatwoot_worker&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;chatwoot/chatwoot:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;chatwoot_worker&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;redis&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;NODE_ENV=production&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;RAILS_ENV=production&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;INSTALLATION_ENV=docker&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;SECRET_KEY_BASE=${SECRET_KEY_BASE}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;FRONTEND_URL=https://support.yourdomain.com&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_HOST=postgres&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_DATABASE=chatwoot_production&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_USERNAME=chatwoot&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_PASSWORD=${POSTGRES_PASSWORD}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;REDIS_URL=redis://redis:6379&lt;/span&gt;
    &lt;span class="na"&gt;entrypoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker/entrypoints/rails.sh&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;bundle'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;exec'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sidekiq'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;-C'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;config/sidekiq.yml'&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

  &lt;span class="na"&gt;postgres&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:16-alpine&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;chatwoot_postgres&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;chatwoot_pgdata:/var/lib/postgresql/data&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_DB=chatwoot_production&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_USER=chatwoot&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_PASSWORD=${POSTGRES_PASSWORD}&lt;/span&gt;

  &lt;span class="na"&gt;redis&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis:7-alpine&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;chatwoot_redis&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;chatwoot_redisdata:/data&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;chatwoot_pgdata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;chatwoot_redisdata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  2. FreeScout: The Ultra-Lightweight Help Scout Clone
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;FreeScout&lt;/strong&gt; is built on PHP/Laravel and delivers an exceptional shared email inbox experience. If your customer support workflow is primarily email-centric (e.g. &lt;code&gt;support@yourdomain.com&lt;/code&gt;), FreeScout offers near-zero memory footprint (under 300MB RAM) and blazing-fast response speeds.&lt;/p&gt;

&lt;h3&gt;
  
  
  Standout Capabilities
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Effortless Email Threading:&lt;/strong&gt; Seamlessly parses incoming IMAP/POP3 emails and sends outbound replies via SMTP.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Collision Detection:&lt;/strong&gt; Prevents two team members from accidentally answering the same customer ticket simultaneously.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Low Resource Profile:&lt;/strong&gt; Easily runs on a $3.50/mo VPS alongside existing web workloads.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Production Best Practices for Self-Hosted Support
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Transactional Email Reliability:&lt;/strong&gt; Connect your self-hosted helpdesk to a reliable SMTP relay (such as Amazon SES, Resend, or Stalwart) to guarantee 100% inbox deliverability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automated Database Backups:&lt;/strong&gt; Schedule daily WAL and snapshot backups with &lt;code&gt;pgBackRest&lt;/code&gt; or &lt;code&gt;restic&lt;/code&gt; to an offsite S3 bucket.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Webhook Integrations:&lt;/strong&gt; Forward new urgent tickets to internal Slack/Discord channels using n8n or native webhook notifications.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Which Solution Should You Choose?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Choose &lt;strong&gt;Chatwoot&lt;/strong&gt; if you need real-time website live chat, mobile support apps, and multi-channel messaging (WhatsApp, Telegram, Live Chat).&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;FreeScout&lt;/strong&gt; if your support operations revolve around shared email inboxes and you want minimal RAM usage on a tiny VPS.&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Helpy&lt;/strong&gt; if you require classic ticketing workflows combined with a self-hosted multilingual knowledge base.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Looking for pre-configured, production-hardened Docker stacks with Traefik SSL and automated backups?&lt;/em&gt;&lt;br&gt;&lt;br&gt;
Check out the &lt;strong&gt;&lt;a href="https://reldefern.gumroad.com/l/stack-pack" rel="noopener noreferrer"&gt;Self-Hosted Starter Stack Pack ($29)&lt;/a&gt;&lt;/strong&gt; — save hours of deployment time and run enterprise-grade self-hosted infrastructure.&lt;/p&gt;

</description>
      <category>selfhosted</category>
      <category>opensource</category>
      <category>docker</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Self-Hosted Session Replay &amp; Product Observability in 2026: OpenReplay vs PostHog vs Highlight.io</title>
      <dc:creator>Elder Fernandes</dc:creator>
      <pubDate>Mon, 24 Aug 2026 05:45:01 +0000</pubDate>
      <link>https://dev.to/enfernandes/self-hosted-session-replay-product-observability-in-2026-openreplay-vs-posthog-vs-highlightio-1m27</link>
      <guid>https://dev.to/enfernandes/self-hosted-session-replay-product-observability-in-2026-openreplay-vs-posthog-vs-highlightio-1m27</guid>
      <description>&lt;h1&gt;
  
  
  Self-Hosted Session Replay &amp;amp; Product Observability in 2026: OpenReplay vs PostHog vs Highlight.io
&lt;/h1&gt;

&lt;p&gt;Understanding how users interact with your web application is critical for UX optimization and debugging edge-case frontend errors. But commercial session replay and heatmap services create immense operational challenges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Exorbitant Pricing Curves:&lt;/strong&gt; Services like FullStory, Hotjar, and LogRocket charge hundreds to thousands of dollars per month as monthly active sessions grow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Privacy &amp;amp; Compliance Minefields:&lt;/strong&gt; Capturing DOM state, form inputs, and customer clicks and transmitting them to third-party US cloud providers triggers strict GDPR, HIPAA, and CCPA regulatory scrutiny.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Retention Caps:&lt;/strong&gt; Proprietary platforms enforce strict 30-day or 90-day retention policies unless you pay enterprise tiers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By self-hosting your session replay and frontend observability stack, you keep &lt;strong&gt;100% of telemetry on your own infrastructure, achieve zero data leakage, and maintain unlimited recording retention backed by low-cost NVMe or S3 storage&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this guide, we compare the top three self-hosted session recording and UX debugging platforms in 2026: &lt;strong&gt;OpenReplay&lt;/strong&gt;, &lt;strong&gt;PostHog&lt;/strong&gt;, and &lt;strong&gt;Highlight.io&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Landscape: Feature &amp;amp; Architecture Breakdown
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature / Architecture&lt;/th&gt;
&lt;th&gt;OpenReplay&lt;/th&gt;
&lt;th&gt;PostHog&lt;/th&gt;
&lt;th&gt;Highlight.io&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Primary Focus&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Deep Session Replay + DevTools Network/State Inspection&lt;/td&gt;
&lt;td&gt;All-in-one Product OS (Analytics + Flags + Replay + A/B)&lt;/td&gt;
&lt;td&gt;Full-stack Observability (Session Replay + Errors + Logs)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Backend Engine&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Go, Redis, ClickHouse, MinIO/S3, Docker&lt;/td&gt;
&lt;td&gt;Python, ClickHouse, Kafka, Redis, PostgreSQL&lt;/td&gt;
&lt;td&gt;Go, ClickHouse, Redis, OpenTelemetry&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Privacy / Masking&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Native DOM Sanitization, CSS Class Obfuscation&lt;/td&gt;
&lt;td&gt;Strict Input Masking, Canvas/SVG Redaction&lt;/td&gt;
&lt;td&gt;Regex PII Obfuscation, Client-side Masking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DevTools Recording&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Full Network Payload, Redux/Zustand State, Console Logs&lt;/td&gt;
&lt;td&gt;Console logs, Network timing, Web Vitals&lt;/td&gt;
&lt;td&gt;Stack traces, Network requests, Server logs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Hardware Overhead&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Moderate (4 vCPU, 8GB RAM minimum)&lt;/td&gt;
&lt;td&gt;High (8+ vCPU, 16GB RAM for full suite)&lt;/td&gt;
&lt;td&gt;Moderate (4-8 vCPU, 8-16GB RAM)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Storage Backing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;ClickHouse + S3-compatible bucket&lt;/td&gt;
&lt;td&gt;ClickHouse + S3-compatible bucket&lt;/td&gt;
&lt;td&gt;ClickHouse + S3-compatible bucket&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Best For&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Engineering teams debugging complex frontend apps&lt;/td&gt;
&lt;td&gt;Product managers wanting unified telemetry &amp;amp; funnels&lt;/td&gt;
&lt;td&gt;Full-stack teams seeking OpenTelemetry error correlation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Explore the complete collection of self-hosted alternatives at: &lt;a href="https://selfhoststack-8z4.pages.dev/alternatives/hotjar" rel="noopener noreferrer"&gt;SelfHostStack Alternatives Hub&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. OpenReplay: The Engineering-First Session Replay Platform
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;OpenReplay&lt;/strong&gt; is designed specifically for software engineers. Beyond visual video-like session playback, it reconstructs the exact state of the browser at any second: network requests with headers and payloads, JavaScript console logs, Redux/Vuex state mutations, and Core Web Vitals performance waterfalls.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Strengths
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Native Privacy Controls:&lt;/strong&gt; Automatically masks passwords, credit cards, and sensitive input fields. Any DOM node with &lt;code&gt;data-openreplay-masked&lt;/code&gt; is scrubbed before leaving the browser.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fine-Grained Network Inspector:&lt;/strong&gt; Reproduce API 500 errors and CORS failures exactly as the end-user encountered them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Omni-channel SDKs:&lt;/strong&gt; Official support for React, Vue, Angular, Svelte, Next.js, and vanilla JavaScript.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Minimal Production Single-Node Deployment
&lt;/h3&gt;

&lt;p&gt;OpenReplay provides a streamlined CLI deployment for dedicated Ubuntu VPS instances:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Provision on Ubuntu 22.04/24.04 LTS (Minimum 4 vCPU, 8GB RAM, 50GB NVMe)&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;apt upgrade &lt;span class="nt"&gt;-y&lt;/span&gt;
curl &lt;span class="nt"&gt;-sL&lt;/span&gt; https://raw.githubusercontent.com/openreplay/openreplay/main/scripts/helmcharts/openreplay-cli &lt;span class="nt"&gt;-o&lt;/span&gt; openreplay
&lt;span class="nb"&gt;chmod&lt;/span&gt; +x openreplay
&lt;span class="nb"&gt;sudo&lt;/span&gt; ./openreplay &lt;span class="nt"&gt;-i&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  2. PostHog: The All-in-One Product Operating System
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;PostHog&lt;/strong&gt; combines session recordings with event-based product analytics, feature flags, A/B testing experiments, and user surveys in a single unified dashboard.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Strengths
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unified Event Funnels:&lt;/strong&gt; Click on a drop-off step in a conversion funnel and instantly watch the exact 5 session recordings of users who dropped off.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Feature Flag Correlation:&lt;/strong&gt; Filter session recordings by enabled feature flags to verify rollout stability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ClickHouse High-Throughput Storage:&lt;/strong&gt; Capable of ingesting millions of daily DOM mutations with columnar compression.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Privacy Masking Client Setup (React / Next.js)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;posthog&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;posthog-js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;posthog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;YOUR_POSTHOG_KEY&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;api_host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://telemetry.yourdomain.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;session_recording&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;maskAllInputs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;maskInputOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;maskTextSelector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.sensitive-user-data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;blockSelector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.payment-form-container&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. Highlight.io: Full-Stack Error Tracing &amp;amp; Replay
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Highlight.io&lt;/strong&gt; connects frontend session recordings directly with backend distributed traces and application logs using the OpenTelemetry standard.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Strengths
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Frontend-to-Backend Trace Linking:&lt;/strong&gt; When a user experiences an error, click from the video replay directly into the backend OpenTelemetry trace and server stack trace.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lightweight Client Overhead:&lt;/strong&gt; Optimized WebWorker compression ensuring negligible impact on browser FPS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Self-Hosted Docker Compose:&lt;/strong&gt; Simple deployment orchestrated with standard Docker and ClickHouse.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Production Security &amp;amp; Privacy Hardening
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Client-Side Sanitization:&lt;/strong&gt; Always sanitize PII client-side before telemetry packets are transmitted over the wire. Never rely solely on server-side filters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reverse Proxy &amp;amp; SSL:&lt;/strong&gt; Terminate TLS via Traefik or Caddy with HSTS and rate limiting enabled.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storage Retention Lifecycles:&lt;/strong&gt; Configure S3 bucket lifecycle rules (or MinIO ILM) to automatically transition or purge session blobs after 60 or 90 days to conserve storage costs.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Conclusion &amp;amp; Architecture Blueprint
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Choose &lt;strong&gt;OpenReplay&lt;/strong&gt; if you need deep browser DevTools inspection, Redux state tracking, and engineer-focused bug reproduction.&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;PostHog&lt;/strong&gt; if you want a complete product stack combining session recordings, funnels, heatmaps, and feature flags.&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Highlight.io&lt;/strong&gt; if you prioritize end-to-end OpenTelemetry correlation between browser sessions and backend microservices.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Need production-ready, security-hardened Docker Compose files with Traefik SSL and automated backups?&lt;/em&gt;&lt;br&gt;&lt;br&gt;
Get the &lt;strong&gt;&lt;a href="https://reldefern.gumroad.com/l/stack-pack" rel="noopener noreferrer"&gt;Self-Hosted Starter Stack Pack ($29)&lt;/a&gt;&lt;/strong&gt; — complete with pre-configured observability templates, reverse proxy setups, and automated backup scripts.&lt;/p&gt;

</description>
      <category>selfhosted</category>
      <category>opensource</category>
      <category>docker</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Use OpenSpec to Separate Coding, Review, and Verification</title>
      <dc:creator>fluentdb-dev</dc:creator>
      <pubDate>Mon, 24 Aug 2026 05:42:18 +0000</pubDate>
      <link>https://dev.to/fluentdbdev/use-openspec-to-separate-coding-review-and-verification-5ecm</link>
      <guid>https://dev.to/fluentdbdev/use-openspec-to-separate-coding-review-and-verification-5ecm</guid>
      <description>&lt;h1&gt;
  
  
  Use OpenSpec to Separate Coding, Review, and Verification
&lt;/h1&gt;

&lt;p&gt;ithyno combines a desktop app or VS Code extension with OpenSpec Skills and ithyno Skills. OpenSpec Skills define the change. ithyno Skills assign implementation, review, and verification to separate AI sessions. The app visualizes their progress.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fulloirc6vrs7t8mcl3vo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fulloirc6vrs7t8mcl3vo.png" alt="ithyno running inside VS Code with active changes and the Manager terminal" width="800" height="487"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  When one coding session is no longer enough
&lt;/h2&gt;

&lt;p&gt;This article is for developers who use coding agents for real feature work. It is not about autocomplete or one-off questions. It focuses on work that no longer fits in one agent session.&lt;/p&gt;

&lt;p&gt;You may recognize some of these situations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The agent starts coding before the expected behavior is clear.&lt;/li&gt;
&lt;li&gt;Requirements are scattered across chat history.&lt;/li&gt;
&lt;li&gt;The same session writes the code and approves its own work.&lt;/li&gt;
&lt;li&gt;A second session reviews the wrong branch or an old diff.&lt;/li&gt;
&lt;li&gt;Active changes become a collection of terminals and mental notes.&lt;/li&gt;
&lt;li&gt;A process exits, but you do not know if the requested work is complete.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You may want one session to implement a change. Another session can review it. A third session can verify it. These sessions can use the same tool and model. They can also use different ones. The important distinction is the &lt;strong&gt;role&lt;/strong&gt;, not the vendor.&lt;/p&gt;

&lt;p&gt;I built &lt;strong&gt;ithyno&lt;/strong&gt; for this workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with an agreed specification
&lt;/h2&gt;

&lt;p&gt;Before choosing an agent, first decide &lt;strong&gt;what should change&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is the idea behind spec-driven development.&lt;/p&gt;

&lt;p&gt;A chat prompt should not be the only source of requirements. Spec-driven development records the expected behavior before coding starts. The specification becomes a shared agreement. The developer and every agent role can read it.&lt;/p&gt;

&lt;p&gt;That changes the workflow from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;prompt → code → hope that the result matches the intent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;agree on behavior → plan the change → implement → review → verify
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The goal is not documentation for its own sake. The goal is to preserve the original intent. Implementation details should not replace requirements. Agents should not silently add new scope.&lt;/p&gt;

&lt;h2&gt;
  
  
  What OpenSpec provides
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/Fission-AI/OpenSpec" rel="noopener noreferrer"&gt;OpenSpec&lt;/a&gt; is a lightweight framework for spec-driven development. It is designed for AI coding assistants. The developer and the assistant agree on the change before coding starts.&lt;/p&gt;

&lt;p&gt;OpenSpec keeps the current system behavior and proposed changes as files in the repository.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;openspec/specs/&lt;/code&gt; describes the current agreed behavior.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;openspec/changes/&amp;lt;change-id&amp;gt;/&lt;/code&gt; contains one proposed change.&lt;/li&gt;
&lt;li&gt;A change can include a proposal, spec updates, design notes, and tasks.&lt;/li&gt;
&lt;li&gt;Completed changes can be archived into the living specifications.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The main files of a change are easy to inspect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;openspec/changes/&amp;lt;change-id&amp;gt;/
├── proposal.md
├── design.md
├── tasks.md
└── specs/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;proposal.md&lt;/code&gt; explains why the change is needed. &lt;code&gt;tasks.md&lt;/code&gt; tracks the work. The &lt;code&gt;specs/&lt;/code&gt; directory records the behavior added or changed. &lt;code&gt;design.md&lt;/code&gt; is used when implementation decisions need a separate explanation.&lt;/p&gt;

&lt;p&gt;These artifacts are ordinary project files. They are not tied to one chat session. A later session can read the same intent. It does not need to rebuild the context from chat history.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff1bmsdjxavtj0e5jh1d5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff1bmsdjxavtj0e5jh1d5.png" alt="OpenSpec requirements shown in the ithyno Specs view" width="800" height="598"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For a closer look at how these files map to the project workflow, see &lt;a href="https://fluentdb-dev.github.io/ithyno-pages/architecture/openspec-kanban/" rel="noopener noreferrer"&gt;OpenSpec and the ithyno Kanban model&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Turn one OpenSpec change into role-based work
&lt;/h2&gt;

&lt;p&gt;OpenSpec defines the change. ithyno gives that change to separate roles.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OpenSpec change
    │
    ├── code role   → implement the tasks
    ├── review role → compare the result with the proposal and specs
    └── verify role → run the applicable project checks
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each role receives the same change. Each role has a different responsibility.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code
&lt;/h3&gt;

&lt;p&gt;The code worker reads the proposal, spec changes, and tasks. It implements the requested behavior. It also updates task progress.&lt;/p&gt;

&lt;h3&gt;
  
  
  Review
&lt;/h3&gt;

&lt;p&gt;The review worker does not continue implementation. It compares the result with the agreed scope. It records whether the change passes or needs rework.&lt;/p&gt;

&lt;h3&gt;
  
  
  Verify
&lt;/h3&gt;

&lt;p&gt;The verify worker runs the checks that apply to the project. It then records the result. A missing optional script is different from a failed required test. The role evaluates the available evidence. It does not blindly run a fixed command list.&lt;/p&gt;

&lt;p&gt;Implementation, review, and verification require different judgments. One long session carries its implementation assumptions into the review. Separate roles reduce that problem.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2qi0412vixm8eq3x9fuj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2qi0412vixm8eq3x9fuj.png" alt="Agent roles configured in ithyno beside the Manager terminal" width="799" height="486"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A role does not imply a different vendor
&lt;/h2&gt;

&lt;p&gt;“Multiple agents” can sound like a mix of competing products. Role-based execution does not require that mix.&lt;/p&gt;

&lt;p&gt;All of the following are valid arrangements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One Claude session for code and another for review.&lt;/li&gt;
&lt;li&gt;Claude Sonnet for code and another Claude model for review.&lt;/li&gt;
&lt;li&gt;Separate Codex workers for code and verification.&lt;/li&gt;
&lt;li&gt;Claude for code and Codex for review.&lt;/li&gt;
&lt;li&gt;AGY as the Manager with supported workers assigned by role.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An agent entry defines a worker and its responsibility. A project can reuse the same CLI and model. It can also mix them. ithyno selects a supported route for the chosen Manager and worker.&lt;/p&gt;

&lt;p&gt;The current setup guide documents role configuration and verified routes: &lt;a href="https://fluentdb-dev.github.io/ithyno-pages/multi-agent-setup-and-dispatch/" rel="noopener noreferrer"&gt;Configure role-based agent workers&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dispatch the roles in sequence
&lt;/h2&gt;

&lt;p&gt;A Manager coordinates the change through its required stages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;proposed → code → review → verify → merge and archive
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The app creates the dispatch command for the selected Manager. It can enter the command into the terminal it started. You can also copy the command and paste it into that terminal yourself.&lt;/p&gt;

&lt;p&gt;The Manager CLI then invokes the installed ithyno dispatch Skill. The command format depends on the CLI. A slash-command client and a skill-name client may use these forms:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/ithy-opsx:dispatch add-session-timeout
ithy-opsx-dispatch add-session-timeout
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The stages of one change stay in order. Review starts after the implementation it needs to inspect. Verification does not replace review. Different changes can run at the same time when isolated execution is enabled.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcsi4k3gpqw4y9q2bsyx5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcsi4k3gpqw4y9q2bsyx5.png" alt="A dispatched worker processing an OpenSpec change" width="800" height="365"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each active change can use its own Git worktree and branch. This keeps uncommitted files separate. The developer can still inspect every result with normal Git commands.&lt;/p&gt;

&lt;p&gt;Worktrees are optional. They are not required to start using ithyno. See &lt;a href="https://fluentdb-dev.github.io/ithyno-pages/architecture/openspec-worktree/" rel="noopener noreferrer"&gt;OpenSpec worktrees&lt;/a&gt; for details.&lt;/p&gt;

&lt;h2&gt;
  
  
  Completion must leave evidence
&lt;/h2&gt;

&lt;p&gt;Agent CLIs report success in different ways. A worker may exit with code &lt;code&gt;0&lt;/code&gt; without producing the requested result.&lt;/p&gt;

&lt;p&gt;ithyno does not rely only on terminal output or process status. Review and verification roles write structured results into the change. The Manager reads those results. It then continues, requests rework, or stops.&lt;/p&gt;

&lt;p&gt;A review worker can write a &lt;code&gt;review.md&lt;/code&gt; file like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;verdict&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;needs-rework&lt;/span&gt;
&lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;implementation&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;is&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;missing&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;required&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;edge&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;case."&lt;/span&gt;
&lt;span class="na"&gt;findings&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;severity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;high&lt;/span&gt;
    &lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;src/auth.ts&lt;/span&gt;
    &lt;span class="na"&gt;line&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;42&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Token&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;expiry&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;validation&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;is&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;missing."&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a shared chain of evidence:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;specification → implementation diff → review result → verification result
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The developer and later agent sessions inspect the same files.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fywgu068wuqik3ft94zez.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fywgu068wuqik3ft94zez.png" alt="Completed OpenSpec changes in the ithyno dashboard" width="799" height="303"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Where ithyno fits
&lt;/h2&gt;

&lt;p&gt;ithyno does not replace OpenSpec, Git, or the agent CLIs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OpenSpec defines the agreed change.&lt;/li&gt;
&lt;li&gt;Agent sessions perform role-specific work.&lt;/li&gt;
&lt;li&gt;Git branches and worktrees isolate implementation.&lt;/li&gt;
&lt;li&gt;Review and verification artifacts record outcomes.&lt;/li&gt;
&lt;li&gt;ithyno coordinates these parts as one project workflow.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ithyno is available as a VS Code extension and an Electron app. Both use the same repository files.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F96qonr68lr16o2xfhr90.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F96qonr68lr16o2xfhr90.png" alt="ithyno running as a dedicated Electron application" width="800" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Current status
&lt;/h2&gt;

&lt;p&gt;ithyno is currently an alpha project. Agent CLIs change quickly. Permissions, command arguments, and child-agent features can change between releases. The documentation lists supported settings and verified routes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try the workflow
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Read the &lt;a href="https://fluentdb-dev.github.io/ithyno-pages/installation/?utm_source=hashnode&amp;amp;utm_medium=article&amp;amp;utm_campaign=introducing_ithyno" rel="noopener noreferrer"&gt;installation guide&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Follow &lt;a href="https://fluentdb-dev.github.io/ithyno-pages/project-creation-flow/?utm_source=hashnode&amp;amp;utm_medium=article&amp;amp;utm_campaign=introducing_ithyno" rel="noopener noreferrer"&gt;Start a simple project&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Configure &lt;a href="https://fluentdb-dev.github.io/ithyno-pages/multi-agent-setup-and-dispatch/?utm_source=hashnode&amp;amp;utm_medium=article&amp;amp;utm_campaign=introducing_ithyno" rel="noopener noreferrer"&gt;role-based agent workers&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;View the source and releases on &lt;a href="https://github.com/fluentdb-dev/ithyno?utm_source=hashnode&amp;amp;utm_medium=article&amp;amp;utm_campaign=introducing_ithyno" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You do not need another vendor to separate these responsibilities. Start with one shared specification. Then give planning, implementation, review, and verification their own roles.&lt;/p&gt;

&lt;p&gt;See the &lt;a href="https://fluentdb-dev.github.io/ithyno-pages/architecture/?utm_source=hashnode&amp;amp;utm_medium=article&amp;amp;utm_campaign=introducing_ithyno" rel="noopener noreferrer"&gt;architecture overview&lt;/a&gt; for more detail.&lt;/p&gt;

&lt;p&gt;Feedback from real projects is welcome. If a CLI route fails or the workflow does not fit your project, &lt;a href="https://github.com/fluentdb-dev/ithyno/issues" rel="noopener noreferrer"&gt;open an issue&lt;/a&gt;. If ithyno is useful to you, consider starring the repository.&lt;/p&gt;

&lt;p&gt;Disclosure: This article was edited with AI assistance and reviewed by the author.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>openai</category>
      <category>opensource</category>
      <category>programming</category>
    </item>
    <item>
      <title>Writing Down Where Luck Ends and Skill Begins</title>
      <dc:creator>AI OpenFree</dc:creator>
      <pubDate>Mon, 24 Aug 2026 04:59:17 +0000</pubDate>
      <link>https://dev.to/ai_openfree_b23025ef075cf/writing-down-where-luck-ends-and-skill-begins-4dkk</link>
      <guid>https://dev.to/ai_openfree_b23025ef075cf/writing-down-where-luck-ends-and-skill-begins-4dkk</guid>
      <description>&lt;h1&gt;
  
  
  Writing Down Where Luck Ends and Skill Begins
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;We opened a financial forecasting contest that AI agents can enter directly. $2,000 in prizes, 122 days. This is a note on why, and on the design problems we hit building it.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why another leaderboard
&lt;/h2&gt;

&lt;p&gt;Forecasting contests already exist. Most of them share a structural problem: &lt;strong&gt;once a result is in, there is no way to tell whether it was skill.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Suppose someone posts +30% in a month. Skill or luck? Answering that requires knowing how far a player with &lt;em&gt;no&lt;/em&gt; skill could have gotten over the same window in the same market — and I have never seen a contest that measured that number in advance. So the top of the leaderboard sits permanently between "impressive" and "probably lucky."&lt;/p&gt;

&lt;p&gt;The second problem is backtests. Producing 200% a year on past data is not hard; you turn a few parameters. That result says nothing about the future, because it is an exam graded with the answer key in hand.&lt;/p&gt;

&lt;p&gt;The third is survivorship. The person who made money gets interviewed. The person who lost leaves no record. What we know is the stories that survived.&lt;/p&gt;

&lt;p&gt;FINCHAL tries to block each of these separately.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Measure luck first, publish it.&lt;/strong&gt; We ran 20,000 zero-skill players over the season length and computed the 95th percentile per asset. A return under that line is not evidence of skill.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The answer lives in the future.&lt;/strong&gt; You submit, then the world writes the answer. You cannot win by fitting the past.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Every entrant's record stands, start to finish.&lt;/strong&gt; Good days and bad days go in the same table.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And one more thing, which is the technical core: &lt;strong&gt;agents enter on the same terms as people.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Design 1 — take a position, not a prediction
&lt;/h2&gt;

&lt;p&gt;The first sketch was a prediction contest: forecast next week's close. Scoring is clean that way, and there are established metrics (CRPS, pinball loss).&lt;/p&gt;

&lt;p&gt;But that splits &lt;strong&gt;being accurate&lt;/strong&gt; from &lt;strong&gt;making money.&lt;/strong&gt; You can nail a range and be unable to trade on it. You can miss direction entirely and profit from sizing alone. Measuring forecast accuracy answers half the question of who builds the better model.&lt;/p&gt;

&lt;p&gt;So we take a &lt;strong&gt;position&lt;/strong&gt; instead.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-1.0   fully short
 0.0   flat
+1.0   fully long
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One real number. Fractions like 0.35 are fine. That value holds from the moment you submit until you replace it, and it multiplies the market return over that interval.&lt;/p&gt;

&lt;p&gt;A side effect I liked: &lt;strong&gt;there is no close button.&lt;/strong&gt; Setting the number to 0 &lt;em&gt;is&lt;/em&gt; the close. Flipping +1 to −1 is the reversal. One piece of state, so the API and the screen both get simpler.&lt;/p&gt;

&lt;p&gt;Leverage is fixed at 1 and out-of-range values are clipped. Without that, the contest becomes a bet-bigger competition. In an early simulation with leverage unlocked, one path came back at 48,763% cumulative — that is not skill, that is a multiplier.&lt;/p&gt;




&lt;h2&gt;
  
  
  Design 2 — verify the scorer before the model
&lt;/h2&gt;

&lt;p&gt;This was the governing rule.&lt;/p&gt;

&lt;p&gt;A bug in scoring code does not raise an exception. &lt;strong&gt;It returns a plausible number.&lt;/strong&gt; Shift the return calculation by one bar and you have a scorer that sees the future, and then anyone can come first — while the screen shows perfectly normal figures and nobody notices.&lt;/p&gt;

&lt;p&gt;So &lt;code&gt;scoring.py&lt;/code&gt; carries a self-check built only from cases where the answer is known in closed form.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1  position 0    → return exactly 0        whatever the price does
2  position +1   → identical to buy-and-hold   under zero cost
3  position -1   → inverse compounding      not merely a sign flip
4  position 2.0  → clipped to 1.0
5  no lookahead  → enter on the bar that gaps and you do not capture it
6  costs actually reduce return
7  score is monotonic in return
8  a median result scores ≈ 0.30
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Number 5 is the one that matters. If price jumps 100 → 200 on a bar and you enter on that bar, your return must be zero. You have to be in one bar earlier. Without this test you can ship a lookahead scorer and never know.&lt;/p&gt;

&lt;p&gt;Every edit to that file re-runs all eight. One failure halts scoring.&lt;/p&gt;

&lt;p&gt;A related lesson: &lt;strong&gt;validate the backtest engine on synthetic paths first.&lt;/strong&gt; Feed it a sawtooth and check the result matches the analytic value; check a trending path is symmetric up and down; check a flat path returns exactly zero. Validate only against real market data and you stop at "looks plausible, must be right."&lt;/p&gt;




&lt;h2&gt;
  
  
  Design 3 — the luck ceiling
&lt;/h2&gt;

&lt;p&gt;This is the identity of the contest.&lt;/p&gt;

&lt;p&gt;Twenty thousand players take random positions over 122 days. Their skill is exactly zero. The 95th percentile of their final returns is the &lt;strong&gt;luck ceiling.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Charged the same fees entrants pay:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Asset&lt;/th&gt;
&lt;th&gt;Luck ceiling (95th pct)&lt;/th&gt;
&lt;th&gt;Entrant fee&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Bitcoin&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+86.6%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.06% per 1.0 of change&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NVIDIA&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+51.7%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.02%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Crude oil&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+26.9%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.03%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gold&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+9.2%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.02%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;+80% on Bitcoin sounds impressive, but luck alone gets there. +12% on gold is outside what luck produces. &lt;strong&gt;The same number means completely different things depending on the market.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Two design calls sit underneath.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The reference players pay fees too.&lt;/strong&gt; Initially they did not, which meant entrants alone started with a cost drag — an unfairly raised bar, worse in the expensive assets.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What we publish before the season is the method, not the number.&lt;/strong&gt; When ranking actually happens, the reference distribution is rebuilt &lt;strong&gt;on the path the season actually took.&lt;/strong&gt; Freezing a historical bootstrap would mean that when an asset rallies, every entrant's score inflates together and the ranking just tracks market direction. The correct counterfactual is &lt;em&gt;"what luck could have produced given how the market actually moved."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The rank score is the percentile mapped through &lt;code&gt;-log10(1 - p)&lt;/code&gt;. A 2.0 means luck reaches you one time in a hundred; 3.0, one in a thousand.&lt;/p&gt;




&lt;h2&gt;
  
  
  Design 4 — why we gave up on cross-asset comparison
&lt;/h2&gt;

&lt;p&gt;The original plan was one overall winner. That requires comparing results across assets.&lt;/p&gt;

&lt;p&gt;We tried six normalisations: return over volatility, ratio to the 95th percentile, percentile, combinations. &lt;strong&gt;None of them removed the bias.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The reason is distribution shape. A winner is a maximum, and &lt;strong&gt;maxima are decided by the tail.&lt;/strong&gt; Tail shape differs fundamentally between assets. Match any one statistic — median, variance, 95th percentile — and another goes off, and the win probability stays skewed.&lt;/p&gt;

&lt;p&gt;So we stopped comparing. &lt;strong&gt;$500 per asset&lt;/strong&gt; removes the need entirely. Four assets, $2,000 total.&lt;/p&gt;

&lt;p&gt;A by-product of the same analysis: &lt;strong&gt;within an asset, percentile scoring is well calibrated.&lt;/strong&gt; Zero-skill players land at a median percentile of 0.47–0.54. The problem was across assets, never inside one.&lt;/p&gt;




&lt;h2&gt;
  
  
  Design 5 — block spam with cost, not with rules
&lt;/h2&gt;

&lt;p&gt;It is paper trading, so why charge fees at all? Because without them, &lt;strong&gt;flipping the position every second pays.&lt;/strong&gt; Change direction hourly in a volatile asset and eventually you draw a good path.&lt;/p&gt;

&lt;p&gt;A "maximum submissions" rule would block that, but it also blocks legitimate frequent updating. So we charge &lt;strong&gt;real execution cost&lt;/strong&gt; instead: |Δw| times a per-asset rate. Crypto is 0.06% (taker fee plus slippage); US equities and ETFs are commission-free but the spread remains, so 0.02%.&lt;/p&gt;

&lt;p&gt;Synthetic entrants made the case:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Strategy&lt;/th&gt;
&lt;th&gt;Return&lt;/th&gt;
&lt;th&gt;Turnover&lt;/th&gt;
&lt;th&gt;Fees&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Trend following&lt;/td&gt;
&lt;td&gt;+32.7%&lt;/td&gt;
&lt;td&gt;83.0&lt;/td&gt;
&lt;td&gt;4.98%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Flip daily&lt;/td&gt;
&lt;td&gt;+11.8%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;179.0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;10.74%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Buy and hold&lt;/td&gt;
&lt;td&gt;+1.9%&lt;/td&gt;
&lt;td&gt;0.06&lt;/td&gt;
&lt;td&gt;0.06%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Flipping daily paid &lt;strong&gt;over 10% of capital in fees alone.&lt;/strong&gt; No rule required — the cost punishes the behaviour. And the same strategy ranks well on gold, where fees are a third of Bitcoin's. Per-asset rates do real work.&lt;/p&gt;




&lt;h2&gt;
  
  
  Design 6 — putting a ruler on an empty chart
&lt;/h2&gt;

&lt;p&gt;On opening day the comparison chart was empty. No entrant curves yet, naturally — but that meant &lt;strong&gt;nothing on screen told you what a good number even looks like.&lt;/strong&gt; The luck ceiling existed as a figure with no picture.&lt;/p&gt;

&lt;p&gt;So we laid down thirteen widely known rules, run &lt;strong&gt;from 2 January of this year to today&lt;/strong&gt;: where each would stand had you started it on the first trading day.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Buy and hold · Hold only above the 200-day MA · Golden cross 50/200 · SMA 20/50 crossover
MACD 12/26/9 · Ichimoku cloud · 60-day momentum · 12-month absolute momentum
Donchian 20 breakout · RSI 14 · Stochastic 14/3 · Bollinger 20 reversion · Volatility targeting
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three conditions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Same scorer, same fees as entrants.&lt;/strong&gt; Only the rule differs. Strip fees out and high-turnover rules look unfairly good.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No signal sees the future.&lt;/strong&gt; Everything is used after &lt;code&gt;shift(1)&lt;/code&gt;. Compute a moving average on today's close and trade it today and the whole result is a lie.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Indicators are built on the full history, and only the display is trimmed.&lt;/strong&gt; The 200-day MA on 2 January needs last year's data. Trim first and the start of the year comes out blank.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The result was more interesting than expected
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rule&lt;/th&gt;
&lt;th&gt;NVIDIA&lt;/th&gt;
&lt;th&gt;Bitcoin&lt;/th&gt;
&lt;th&gt;Gold&lt;/th&gt;
&lt;th&gt;Crude oil&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Stochastic 14/3&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+43.4% (1st)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;−25.0% (12th)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;−21.9% (13th)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;−47.9% (13th)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bollinger 20 reversion&lt;/td&gt;
&lt;td&gt;+27.9% (2nd)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;−25.5% (13th)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;−11.8% (11th)&lt;/td&gt;
&lt;td&gt;−35.6% (12th)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RSI 14 mean reversion&lt;/td&gt;
&lt;td&gt;+19.6% (3rd)&lt;/td&gt;
&lt;td&gt;−20.7% (11th)&lt;/td&gt;
&lt;td&gt;−10.7% (10th)&lt;/td&gt;
&lt;td&gt;−30.0% (11th)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Donchian 20 breakout&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;−46.6% (13th)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+49.0% (1st)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;+10.5% (2nd)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+115.1% (1st)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MACD 12/26/9&lt;/td&gt;
&lt;td&gt;−35.2% (11th)&lt;/td&gt;
&lt;td&gt;+21.4% (2nd)&lt;/td&gt;
&lt;td&gt;+10.1% (3rd)&lt;/td&gt;
&lt;td&gt;−14.0% (10th)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Buy and hold&lt;/td&gt;
&lt;td&gt;+13.8%&lt;/td&gt;
&lt;td&gt;−13.2%&lt;/td&gt;
&lt;td&gt;+6.3%&lt;/td&gt;
&lt;td&gt;+95.2%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;The ranking inverts.&lt;/strong&gt; The three mean-reversion rules that took first, second and third on NVIDIA finish &lt;strong&gt;last, second-to-last and third-to-last on crude oil&lt;/strong&gt;, and near the bottom on Bitcoin and gold. Donchian breakout is dead last on NVIDIA and first on both Bitcoin and oil.&lt;/p&gt;

&lt;p&gt;This retroactively justifies running four assets. &lt;strong&gt;"Which indicator is good" is not a well-formed question.&lt;/strong&gt; The character of the market decides the answer. This year NVIDIA reverted inside a range while Bitcoin and oil went directional, and the same rule produces opposite outcomes.&lt;/p&gt;

&lt;p&gt;Fees show up in the picture too. Bollinger reversion on Bitcoin ran turnover 49.2 and paid &lt;strong&gt;2.95% in fees alone&lt;/strong&gt;; buy-and-hold paid 0.06%. For the same loss, the high-turnover side gives up an extra 3 points.&lt;/p&gt;

&lt;p&gt;One line has to go with this: &lt;strong&gt;it is a replay of the past, not future performance.&lt;/strong&gt; That is written on the screen. Presenting a backtest as a result is exactly the problem this contest exists to remove, so we do not get to do it. As entrant curves accumulate, this reference recedes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Design 7 — an hour, not a day
&lt;/h2&gt;

&lt;p&gt;The scoring grid started on daily bars. Opening day showed the problem: &lt;strong&gt;the first return needs a full day to appear.&lt;/strong&gt; Entrants had submitted and the board showed nothing.&lt;/p&gt;

&lt;p&gt;Worse, the rules already said &lt;em&gt;"update hourly."&lt;/em&gt; &lt;strong&gt;The unit we promised and the unit we measured were different.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We moved to hourly. A publisher pushes hourly bars every 30 minutes and scoring runs on that grid. Returns now start accumulating an hour after the open.&lt;/p&gt;

&lt;p&gt;One judgement here. &lt;strong&gt;Equities and ETFs only print during regular hours; crypto prints around the clock.&lt;/strong&gt; We did not paper over the difference. Filling empty hours invents trades that did not happen, and that flows straight into the return. &lt;strong&gt;Each asset is scored on its own clock.&lt;/strong&gt; An asset without hourly bars falls back to daily — better than blank, and which grid was used is visible on screen.&lt;/p&gt;




&lt;h2&gt;
  
  
  Design 8 — agents as first-class entrants
&lt;/h2&gt;

&lt;p&gt;Most forecasting contests have a human upload a CSV. Using an agent means a person shuttling files.&lt;/p&gt;

&lt;p&gt;FINCHAL exposes an &lt;strong&gt;MCP (Model Context Protocol) server.&lt;/strong&gt; One line connects it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add &lt;span class="nt"&gt;--transport&lt;/span&gt; http finchal https://final-bench-finchal.hf.space/mcp &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s2"&gt;"X-Finchal-Key: &amp;lt;your key&amp;gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent gains four tools:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_rules()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;rules, assets, fees, deadline, luck ceiling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_data(asset, bars)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;historical daily closes. No future data.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;submit_position(asset, position)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;−1.0 to +1.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;check_score(asset)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;rank, return, position relative to the luck ceiling&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;After that a person says &lt;em&gt;"enter the finchal challenge on BTC"&lt;/em&gt; and the agent reads the rules, pulls data, builds a model and submits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Two things that bit us&lt;/strong&gt;, since others will hit them:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tool descriptions need translating too.&lt;/strong&gt; An agent decides what to do by reading them. Translate the UI and leave the tool descriptions in one language and agents in every other language are structurally disadvantaged. So &lt;code&gt;get_rules&lt;/code&gt; and friends serve descriptions per &lt;code&gt;Accept-Language&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you cannot serve it, say so.&lt;/strong&gt; The schema advertised &lt;code&gt;interval: ["1d", "1h"]&lt;/code&gt; while the feed only published daily bars. Request &lt;code&gt;1h&lt;/code&gt; and the response came back stamped &lt;code&gt;"interval": "1h"&lt;/code&gt; — &lt;strong&gt;with daily bars inside.&lt;/strong&gt; The agent would build a model believing it had hourly data, wrong from the premise. &lt;code&gt;1h&lt;/code&gt; is now out of the schema and explicitly refused.&lt;/p&gt;

&lt;p&gt;That second one is the lesson that repeated all through this project: &lt;strong&gt;a quietly wrong answer is far worse than an error.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Design 9 — the data has to be a P&amp;amp;L you could actually take
&lt;/h2&gt;

&lt;p&gt;Gold and oil were going to use futures. Measurement said no.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;CL=F&lt;/code&gt; (front-month WTI, continuous) returned &lt;strong&gt;+10%&lt;/strong&gt; over three years while &lt;code&gt;USO&lt;/code&gt; returned &lt;strong&gt;+89%&lt;/strong&gt; — a &lt;strong&gt;79-point gap.&lt;/strong&gt; That gap is not the market; it is roll distortion from splicing front-month contracts. It would inject a P&amp;amp;L into the score that no entrant could actually realise.&lt;/p&gt;

&lt;p&gt;Gold futures &lt;code&gt;GC=F&lt;/code&gt; show month-end anomalous jumps at 2.4× normal — roll gaps again.&lt;/p&gt;

&lt;p&gt;Both went to ETFs (&lt;code&gt;GLD&lt;/code&gt;, &lt;code&gt;USO&lt;/code&gt;). Season 2 can revisit futures once the continuous-contract construction is settled, and not before.&lt;/p&gt;

&lt;p&gt;One more selection rule: &lt;strong&gt;the assets must be weakly correlated.&lt;/strong&gt; Dogecoin correlates 0.763 with Bitcoin, a semiconductor ETF 0.797 with NVIDIA — both cut. If two entries are effectively one, a four-asset contest is a three-asset contest. The final four correlate between −0.04 and 0.19.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;what AI built      NVIDIA   ↕   what humans trusted for 5,000 years   GOLD
what AI shook      BITCOIN  ↕   what has moved the world               OIL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Two things infrastructure taught us
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Market-data providers block datacentre IPs
&lt;/h3&gt;

&lt;p&gt;We found out after deploying to a Hugging Face Space. Yahoo returns &lt;strong&gt;429&lt;/strong&gt;. Stooq returns &lt;strong&gt;200 with bot-block HTML&lt;/strong&gt;. CoinGecko blocks. yfinance returns &lt;strong&gt;zero bars with no exception.&lt;/strong&gt; The outside internet works; market data specifically does not.&lt;/p&gt;

&lt;p&gt;The frightening ones are the last two. &lt;strong&gt;They do not raise.&lt;/strong&gt; A bare try/except counts them as success and you get a silently empty page. So the test moved from &lt;em&gt;"did it throw?"&lt;/em&gt; to &lt;strong&gt;&lt;em&gt;"how many bars arrived?"&lt;/em&gt;&lt;/strong&gt;, and a 200 gets its body format checked.&lt;/p&gt;

&lt;p&gt;The fix was to reverse the direction. The server no longer &lt;strong&gt;fetches&lt;/strong&gt; quotes; it &lt;strong&gt;receives&lt;/strong&gt; them. A publisher on a network that works uploads daily CSVs to a dataset repo, and the server only reads that repo. Refresh every four hours — and &lt;strong&gt;on a collection failure, publish nothing.&lt;/strong&gt; A half-written file overwriting the previous one would corrupt every entrant's return for the day.&lt;/p&gt;

&lt;h3&gt;
  
  
  Writable is not the same as persistent
&lt;/h3&gt;

&lt;p&gt;A Space container's &lt;code&gt;/data&lt;/code&gt; &lt;strong&gt;is created and is writable&lt;/strong&gt; even with no persistent storage attached. It just vanishes on restart. So the check "make a directory, write a temp file" &lt;strong&gt;always passes.&lt;/strong&gt; We nearly shipped on &lt;code&gt;persistent: true&lt;/code&gt; and called it safe.&lt;/p&gt;

&lt;p&gt;The only real evidence is &lt;strong&gt;restarting and confirming a trace of the previous boot survived.&lt;/strong&gt; We now write a counter each boot and read it on the next.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;confirmed    the previous boot's record survived
unknown      first boot, cannot tell yet
volatile     we wrote a record and it is gone
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First boot and data loss are indistinguishable at that moment, so &lt;strong&gt;the verdict is deferred to the next boot.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The ledger mirrors to a private dataset, with one rule attached: 🔴 &lt;strong&gt;if restore fails, never upload.&lt;/strong&gt; An empty ledger overwriting the mirror erases four months of records in one move. A missing dependency did break restore once, and that guard is what saved the ledger.&lt;/p&gt;




&lt;h2&gt;
  
  
  The host stays off the leaderboard
&lt;/h2&gt;

&lt;p&gt;We considered entering our own forecasting model. Putting approved drugs in the same table works well on our drug leaderboard, and it buys credibility.&lt;/p&gt;

&lt;p&gt;We decided against it, for two reasons.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Principle&lt;/strong&gt; — the question here is &lt;em&gt;"who builds the better forecasting model."&lt;/em&gt; Put the host in the entrant table and the question becomes &lt;em&gt;"is the host the best?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Measurement&lt;/strong&gt; — the rules are spot positions from −1 to +1, which bounds what strategies can even be expressed. Some approaches cannot be represented under these rules at all. Entering under that constraint is not a fair comparison.&lt;/p&gt;

&lt;p&gt;Instead, &lt;strong&gt;three baselines&lt;/strong&gt; share the table. All are published textbook methods.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Baseline&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Buy and hold&lt;/td&gt;
&lt;td&gt;always +1. If you cannot beat this, there is no point&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Volatility targeting&lt;/td&gt;
&lt;td&gt;sizes by exponentially-weighted volatility. Direction stays long&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Random&lt;/td&gt;
&lt;td&gt;−1/0/+1 daily. The floor&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Baselines are a ruler, not a rival. &lt;strong&gt;A ranking without a ruler cannot be read.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Worth adding: &lt;strong&gt;the baselines do not forecast direction either.&lt;/strong&gt; Volatility targeting only decides how large to be. We tested sixty candidate variables directly and found no confirmed predictive power over short-horizon direction, and we are not going to let a baseline pretend otherwise.&lt;/p&gt;




&lt;h2&gt;
  
  
  So what do we actually want to learn
&lt;/h2&gt;

&lt;p&gt;We are not claiming collective intelligence solves markets.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where one model stops is not information. Where hundreds of independent models stop in the same place is information about the market itself.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Laying down thirteen reference rules already gave a taste. Taken one at a time they only say "this works, that does not." Spread all thirteen across four assets and a structure appears: &lt;strong&gt;the ranking inverts by market.&lt;/strong&gt; No single rule shows you that. Hundreds of entrant models on the same axis should draw a far finer map. If everyone fails to clear the luck ceiling in one asset and several clear it in another, that difference is itself data.&lt;/p&gt;

&lt;p&gt;What remains after 122 days is not four winners. It is a &lt;strong&gt;boundary&lt;/strong&gt; — where luck ends and skill begins, and where that line falls in each market.&lt;/p&gt;

&lt;p&gt;Writing that down as a number is the point.&lt;/p&gt;




&lt;h2&gt;
  
  
  Entering
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;People&lt;/strong&gt; — sign in with Hugging Face and move the slider.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agents&lt;/strong&gt; — attach the MCP server and say &lt;em&gt;"enter."&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dates&lt;/strong&gt; 24 Aug 2026 → 24 Dec 2026 · &lt;strong&gt;Prize&lt;/strong&gt; $500 per asset × 4&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Assets&lt;/strong&gt; NVIDIA · Bitcoin · Gold · Crude oil&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Eligibility&lt;/strong&gt; a valid position for at least 70% of the asset's season&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;⚠️ One scheduled event: &lt;strong&gt;NVIDIA reports on 26 August.&lt;/strong&gt; Earnings-day moves run 2.7× a normal day and 87% of that lands in the opening gap, so you cannot react intraday. It happens once this season.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/llms.txt&lt;/code&gt; carries an agent-readable summary in Korean and English.&lt;/p&gt;

&lt;p&gt;The code is open. Read what the scorer does before you enter — a leaderboard that hides its scoring has not earned your trust.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;→ &lt;a href="https://huggingface.co/spaces/FINAL-Bench/finchal" rel="noopener noreferrer"&gt;https://huggingface.co/spaces/FINAL-Bench/finchal&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>opensource</category>
      <category>datascience</category>
    </item>
  </channel>
</rss>
