{"id":50398394,"url":"https://github.com/martinfrancois/java-optionals-skill","last_synced_at":"2026-05-30T22:01:09.691Z","repository":{"id":361407173,"uuid":"1253819603","full_name":"martinfrancois/java-optionals-skill","owner":"martinfrancois","description":"Help AI coding agents use Java Optional well in new code and cleanup, without replacing one antipattern with another.","archived":false,"fork":false,"pushed_at":"2026-05-30T14:56:16.000Z","size":214,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-30T15:07:04.802Z","etag":null,"topics":["ai-coding","ai-tools","best-practices","clean-code","code-quality","code-review","coding-agent","developer-tools","functional-programming","java","java-8","java-optional","llm","llm-agents","openai-codex","optional","optionals","refactoring","skills","tessl"],"latest_commit_sha":null,"homepage":"https://tessl.io/registry/martinfrancois/java-optionals","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/martinfrancois.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-05-29T21:06:01.000Z","updated_at":"2026-05-30T14:56:20.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/martinfrancois/java-optionals-skill","commit_stats":null,"previous_names":["martinfrancois/java-optionals-skill"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/martinfrancois/java-optionals-skill","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/martinfrancois%2Fjava-optionals-skill","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/martinfrancois%2Fjava-optionals-skill/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/martinfrancois%2Fjava-optionals-skill/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/martinfrancois%2Fjava-optionals-skill/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/martinfrancois","download_url":"https://codeload.github.com/martinfrancois/java-optionals-skill/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/martinfrancois%2Fjava-optionals-skill/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33711018,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-30T02:00:06.278Z","response_time":92,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-coding","ai-tools","best-practices","clean-code","code-quality","code-review","coding-agent","developer-tools","functional-programming","java","java-8","java-optional","llm","llm-agents","openai-codex","optional","optionals","refactoring","skills","tessl"],"created_at":"2026-05-30T22:01:08.787Z","updated_at":"2026-05-30T22:01:09.679Z","avatar_url":"https://github.com/martinfrancois.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Java Optional Skill for AI Agents\n\n[![tessl](https://img.shields.io/endpoint?url=https%3A%2F%2Fapi.tessl.io%2Fv1%2Fbadges%2Fmartinfrancois%2Fjava-optionals)](https://tessl.io/registry/martinfrancois/java-optionals)\n\nAI agents often know enough Java to reach for `Optional`, but not enough to use it well.\n\nThey write code that looks modern at first glance, then leaves you with `isPresent()` plus `get()`,\n`orElse(null)`, fallback code that runs too early, fake one-item lists, or a clear stream rewritten\nas a noisy loop.\n\nThis skill gives the agent a small decision guide before it writes or changes Optional code: choose\nthe Optional shape, run fallback work only when needed, keep real collection streams readable, and\nuse a plain branch when checked IO makes that clearer.\n\n## Contents\n\n- [Getting Started](#getting-started)\n- [Why This Exists](#why-this-exists)\n- [What Good Looks Like](#what-good-looks-like)\n- [What It Helps With](#what-it-helps-with)\n- [Examples](#examples)\n- [How It's Evaluated](#how-its-evaluated)\n- [Contributing](#contributing)\n- [Origin](#origin)\n- [License](#license)\n\n## Getting Started\n\n### 1. Install\n\nInstall the published Tessl tile using the option that fits your setup:\n\n| Tool | Command |\n| --- | --- |\n| npm | `npx tessl i martinfrancois/java-optionals` |\n| yarn | `yarn dlx tessl i martinfrancois/java-optionals` |\n| pnpm | `pnpx tessl i martinfrancois/java-optionals` |\n| bun | `bunx tessl i martinfrancois/java-optionals` |\n| Tessl CLI | `tessl i martinfrancois/java-optionals` |\n\nUse one of the package-runner commands if you want to try the skill without installing the Tessl CLI\nfirst.\n\n### 2. Use It\n\nAgents that support skill auto-selection, such as\n[Codex](https://developers.openai.com/codex/skills) and\n[Claude Code](https://code.claude.com/docs/en/skills), can choose this skill automatically from the\ntask or code context. The task doesn't need to say `Optional` by name.\n\nIt can also trigger when Java code deals with missing values, values that may be `null`,\nfallback/default values, `isPresent()`, `orElse(null)`, `optional.stream()`,\n`findFirst()` / `findAny()`, or similar code paths for values that may or may not exist.\n\nFor important Optional-heavy work, you can still name the skill explicitly:\n\n```text\nUse $java-optionals to implement this Java feature with Optional best practices.\n```\n\nFor cleanup work:\n\n```text\nUse $java-optionals to clean up this Java method without changing its outputs or error handling.\n```\n\nFor reviews:\n\n```text\nUse $java-optionals to review this Java Optional code and suggest any cleanups.\n```\n\n## Why This Exists\n\nThe motivation was real AI-written Java code. The agent already used `Optional`, but didn't follow\nbest practices. When asked to clean up the code and follow Optional best practices, it often swapped\none bad pattern for another:\n\n- replacing `isPresent()` / `get()` with `orElse(null)` and local null checks;\n- using `isPresent()` or `isEmpty()` and then reading the same value with `get()` or\n  `orElseThrow()`;\n- running fallback work too early by using `orElse(...)` where `orElseGet(...)` is required;\n- turning one optional value into a fake list, then reading the first item;\n- replacing a clear collection stream with a long manual loop;\n- hiding checked IO or user prompts behind clever helper code;\n- changing the meaning of `findFirst()` / `findAny()` by accident.\n\nThe examples below show Java `Optional` code an AI agent would write, followed by what it would\nchange that code to when asked to follow Optional best practices without this skill.\n\nFor example, one cleanup would have changed a simple coupon branch into a fake list:\n\n```java\n// before the AI cleanup request\nif (selectedCoupon.isPresent()) {\n    return applyCoupon(cart, selectedCoupon.get());\n}\nreturn cart;\n\n// what an unassisted AI would have changed it to\nList\u003cCoupon\u003e coupons = selectedCoupon.stream().toList();\nif (!coupons.isEmpty()) {\n    return applyCoupon(cart, coupons.getFirst());\n}\nreturn cart;\n```\n\nAnother would have changed a product discount fallback into local null checks:\n\n```java\n// before the AI cleanup request\nif (discount.isPresent()) {\n    return price.minus(discount.get());\n}\nreturn price;\n\n// what an unassisted AI would have changed it to\nMoney value = discount.orElse(null);\nif (value != null) {\n    return price.minus(value);\n}\nreturn price;\n```\n\nAnd another would have changed a delivery-slot lookup into a harder-to-read loop:\n\n```java\n// before the AI cleanup request\nfor (DeliveryWindow preferredWindow : preferredWindows) {\n    Optional\u003cDeliverySlot\u003e match = availableSlots.stream()\n            .filter(slot -\u003e slot.fits(preferredWindow))\n            .findFirst();\n    if (match.isPresent()) {\n        return Optional.of(match.orElseThrow());\n    }\n}\nreturn Optional.empty();\n\n// what an unassisted AI would have changed it to\nfor (DeliveryWindow preferredWindow : preferredWindows) {\n    for (DeliverySlot slot : availableSlots) {\n        if (slot.fits(preferredWindow)) {\n            return Optional.of(slot);\n        }\n    }\n}\nreturn Optional.empty();\n```\n\nThe goal isn't to force every branch into a method chain. The goal is simpler: understand what the\n`Optional` is doing, keep the important effects in the same places, and choose the clearest code.\n\n## What Good Looks Like\n\nWithout this skill, agents may \"clean up\" Optional code but still leave the same control-flow\nproblem:\n\n```java\nCoupon coupon = cart.coupon().orElse(null);\n\nif (coupon != null) {\n    return totalWithCoupon(cart, coupon);\n}\nreturn totalWithoutCoupon(cart);\n```\n\nWith this skill, the agent is pushed toward using the `Optional` for the actual decision:\n\n```java\nMoney total(Cart cart) {\n    return cart.coupon()\n            .map(coupon -\u003e totalWithCoupon(cart, coupon))\n            .orElseGet(() -\u003e totalWithoutCoupon(cart));\n}\n```\n\n## What It Helps With\n\nGood fit:\n\n- replacing `isPresent()` or `isEmpty()` followed by `get()` or `orElseThrow()`;\n- avoiding `orElse(null)` followed by local null checks;\n- choosing between `orElse(...)` and `orElseGet(...)`;\n- keeping checked exceptions, user prompts, IO, and side effects in the right place;\n- deciding whether `findFirst()` or `findAny()` keeps the same result;\n- keeping real collection streams instead of rewriting them as noisy loops;\n- avoiding `optional.stream().toList()` loops for a single `Optional`;\n- handling old APIs that really use `null` for missing values;\n- writing new Optional code directly instead of cleaning up hard-to-read branches later.\n\nPoor fit:\n\n- broad Java style enforcement unrelated to `Optional`;\n- large API redesigns, data object changes, or new dependencies without maintainer agreement;\n- changing business behavior just to make code look more functional;\n- replacing every readable branch with a method chain.\n\n## Examples\n\nSimple fallback:\n\n```java\nString customerName(Optional\u003cCustomer\u003e customer) {\n    return customer.map(Customer::name).orElse(\"Guest\");\n}\n```\n\nCreate only when needed:\n\n```java\nCart cart(String cartId) {\n    return carts.find(cartId).orElseGet(() -\u003e createCart(cartId));\n}\n```\n\nSide-effect branch:\n\n```java\nvoid sendReceipt(Order order, Optional\u003cEmail\u003e email) {\n    email.ifPresentOrElse(\n            address -\u003e sendEmail(address, order),\n            () -\u003e printReceipt(order));\n}\n```\n\nChecked IO case where a plain branch is clearer:\n\n```java\nString shippingAddress(Checkout checkout, Console console) throws IOException {\n    Optional\u003cString\u003e saved = checkout.savedShippingAddress();\n    if (saved.isEmpty()) {\n        return console.readLine(\"Shipping address: \");\n    }\n    return saved.orElseThrow();\n}\n```\n\nReal collection lookup:\n\n```java\nOptional\u003cDeliverySlot\u003e deliverySlot(DeliveryWindow preferredWindow) {\n    return availableSlots.stream()\n            .filter(slot -\u003e slot.fits(preferredWindow))\n            .findFirst();\n}\n```\n\n## How It's Evaluated\n\nThe skill is tested on implementation tasks based on real AI-written `Optional` mistakes. Each task\nis run without the skill and with the skill, then scored against checks for both the requested Java\nbehavior and the `Optional` cleanup.\n\nThe evals check that agents:\n\n- avoid `isPresent()` / `get()` for ordinary value reads;\n- don't replace `Optional` with `orElse(null)`;\n- run fallback work only when needed;\n- keep checked IO and user prompts clear;\n- keep real collection streams readable;\n- preserve outputs, errors, prompts, side effects, and when fallback work runs.\n\nCurrent published scores are shown on the\n[Tessl tile](https://tessl.io/registry/martinfrancois/java-optionals).\n\n## Contributing\n\nWant to improve the skill, evals, or package metadata? See [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## Origin\n\nThis skill is based on real-world failures where coding agents changed Java `Optional` code into\ndifferent bad shapes while working on production-style tasks. The motivating discussion is\n[`martin-francois/symphony-trello#96`](https://github.com/martin-francois/symphony-trello/issues/96).\n\nThe skill is self-contained: using it doesn't require access to that issue, the original repository,\ndevelopment drafts, or any external article.\n\n## License\n\nMIT. See [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmartinfrancois%2Fjava-optionals-skill","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmartinfrancois%2Fjava-optionals-skill","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmartinfrancois%2Fjava-optionals-skill/lists"}