From f5be76ed8d7341c2383219fe4720097e619b9465 Mon Sep 17 00:00:00 2001 From: msuarz Date: Tue, 14 Apr 2026 17:35:27 -0400 Subject: [PATCH] take2 --- .claude/dude | 1 + .claude/skills/cupid0/SKILL.md | 44 +++++++++++++++++ .claude/skills/cupid0/indeed.md | 33 +++++++++++++ .claude/skills/cupid0/swipe_left.md | 25 ++++++++++ .claude/skills/cupid0/swipe_right.md | 12 +++++ .formatter.exs | 5 -- .gitignore | 2 + .mcp.json | 8 ++++ CLAUDE.md | 21 ++++++++ apps/bouncer/.formatter.exs | 4 -- apps/bouncer/.gitignore | 26 ---------- apps/bouncer/README.md | 21 -------- apps/bouncer/lib/bouncer.ex | 18 ------- apps/bouncer/lib/bouncer/application.ex | 20 -------- apps/bouncer/mix.exs | 35 -------------- apps/bouncer/test/bouncer_feature_test.exs | 16 ------- apps/bouncer/test/bouncer_test.exs | 8 ---- apps/bouncer/test/cabbage_test.exs | 8 ---- apps/bouncer/test/features/bouncer.feature | 7 --- apps/bouncer/test/test_helper.exs | 1 - config/config.exs | 18 ------- mix.exs | 21 -------- mix.lock | 4 -- resume/golden/ai.md | 37 ++++++++++++++ resume/golden/og.md | 47 ++++++++++++++++++ tcr.sh | 56 ---------------------- 26 files changed, 230 insertions(+), 268 deletions(-) create mode 120000 .claude/dude create mode 100644 .claude/skills/cupid0/SKILL.md create mode 100644 .claude/skills/cupid0/indeed.md create mode 100644 .claude/skills/cupid0/swipe_left.md create mode 100644 .claude/skills/cupid0/swipe_right.md delete mode 100644 .formatter.exs create mode 100644 .mcp.json create mode 100644 CLAUDE.md delete mode 100644 apps/bouncer/.formatter.exs delete mode 100644 apps/bouncer/.gitignore delete mode 100644 apps/bouncer/README.md delete mode 100644 apps/bouncer/lib/bouncer.ex delete mode 100644 apps/bouncer/lib/bouncer/application.ex delete mode 100644 apps/bouncer/mix.exs delete mode 100644 apps/bouncer/test/bouncer_feature_test.exs delete mode 100644 apps/bouncer/test/bouncer_test.exs delete mode 100644 apps/bouncer/test/cabbage_test.exs delete mode 100644 apps/bouncer/test/features/bouncer.feature delete mode 100644 apps/bouncer/test/test_helper.exs delete mode 100644 config/config.exs delete mode 100644 mix.exs delete mode 100644 mix.lock create mode 100644 resume/golden/ai.md create mode 100644 resume/golden/og.md delete mode 100755 tcr.sh diff --git a/.claude/dude b/.claude/dude new file mode 120000 index 0000000..53c01be --- /dev/null +++ b/.claude/dude @@ -0,0 +1 @@ +/Users/mike/.claude \ No newline at end of file diff --git a/.claude/skills/cupid0/SKILL.md b/.claude/skills/cupid0/SKILL.md new file mode 100644 index 0000000..04c4e0f --- /dev/null +++ b/.claude/skills/cupid0/SKILL.md @@ -0,0 +1,44 @@ +--- +name: cupid0 +description: Use when searching, filtering, and evaluating job listings for Mike +--- + +# cupid0 + +Job seeker agent. Finds jobs on Indeed, filters rejects, evaluates matches, tailors resume, applies. + +## Process + +1. **search** — scrape one Indeed page using chrome-devtools MCP (see indeed.md) +2. **filter** — swipe left based on swipe_left.md, run `node filter.js` +3. **report** — show keepers as `company | title | salary`, ask Mike before continuing +4. **next page** — only after Mike gives the go-ahead, repeat steps 1-3 +5. **evaluate** — once all pages done, screen each keeper ONE AT A TIME: fetch full description → save to /tmp/descriptions/.md → score 1-100 vs resume → report → wait → next +6. **tailor** — generate tailored resume per keeper using ai_golden.md + og_golden.md +7. **apply** — fill and submit application + +## Pace Rules — READ THIS + +- **Never parallelize.** Not search, not fetching, not scoring. One thing at a time. +- After each page: report keepers, stop, wait for Mike. +- During evaluate: fetch one description, score it, report it, stop, wait for Mike. +- Natural pauses = natural rate limiting. We have time. Don't rush. +- Going serial also avoids Indeed detection/rate limits. + +## Files + +- `swipe_left.md` — auto-reject criteria +- `swipe_right.md` — green flags that boost score +- `indeed.md` — Indeed-specific scraping instructions + +## Resumes + +- `~/dev/self/portfolio/resume/ai_golden.md` — AI/agentic focus +- `~/dev/self/portfolio/resume/og_golden.md` — full classic experience + +## State + +- `/tmp/suitors.json` — current candidate list +- `/tmp/keepers.json` — keepers across pages +- `/tmp/evals.json` — scores and notes +- `/tmp/descriptions/` — full job descriptions diff --git a/.claude/skills/cupid0/indeed.md b/.claude/skills/cupid0/indeed.md new file mode 100644 index 0000000..58f7649 --- /dev/null +++ b/.claude/skills/cupid0/indeed.md @@ -0,0 +1,33 @@ +--- +name: indeed +description: Use when searching or scraping Indeed job listings for cupid0 +--- + +# Indeed + +## What +Scrape Indeed job listings using the chrome-devtools MCP against the user's real logged-in Chrome session. + +## How + +**Search URL:** +``` +https://www.indeed.com/jobs?q=software+engineer&l=Remote&fromage=7&salaryType=%24150%2C000&sc=0kf%3Aattr%28DSQF7%29%3B +``` + +**Pagination:** append `&start=20` for page 2, `&start=40` for page 3, etc. + +**Scrape jobs with evaluate_script:** +```javascript +() => [...document.querySelectorAll('.job_seen_beacon')].map(el => ({ + title: el.querySelector('.jobTitle a')?.innerText?.trim(), + company: el.querySelector('[data-testid="company-name"]')?.innerText?.trim(), + url: el.querySelector('.jobTitle a')?.href +})).filter(j => j.title) +``` + +**Rules:** +- Use chrome-devtools MCP only — Playwright gets detected on page 2+ +- Do NOT navigate if already on the right page — read first +- After getting jobs from evaluate_script, use Write tool to save to /tmp/cupid0_jobs.json as {"count": N, "jobs": [...]} +- Run `node filter.js` after each page diff --git a/.claude/skills/cupid0/swipe_left.md b/.claude/skills/cupid0/swipe_left.md new file mode 100644 index 0000000..00497b5 --- /dev/null +++ b/.claude/skills/cupid0/swipe_left.md @@ -0,0 +1,25 @@ +# swipe left 🙅 + +auto-reject any job that matches these. no need to fetch the description. + +- government, federal, or public sector +- military, defense, army, dod, or requires security clearance +- religious organizations +- crypto, blockchain, web3, nft, solana +- staffing agencies / body shops (Intone, Wipro, Infosys, TCS, etc.) +- consulting farms that just place you at clients (Accenture, Deloitte, etc.) + +## tech i don't do + +- crypto / blockchain / web3 +- android / mobile +- java +- golang +- devops / sre / platform engineering +- cybersecurity / infosec +- php + +## company stage + +- pre-revenue startups (no salary, equity-only) +- solo engineer / first engineer at non-tech companies (CPA firms, law firms, etc.) diff --git a/.claude/skills/cupid0/swipe_right.md b/.claude/skills/cupid0/swipe_right.md new file mode 100644 index 0000000..525d2e9 --- /dev/null +++ b/.claude/skills/cupid0/swipe_right.md @@ -0,0 +1,12 @@ +# swipe right 🙌 + +auto-bump score for any job mentioning these. rare green flags. + +## culture + +- XP (Extreme Programming) +- pair programming +- mob programming +- TDD / BDD / ATDD +- Kanban +- DDD (Domain-Driven Design) diff --git a/.formatter.exs b/.formatter.exs deleted file mode 100644 index 90a0853..0000000 --- a/.formatter.exs +++ /dev/null @@ -1,5 +0,0 @@ -# Used by "mix format" -[ - inputs: ["mix.exs", "config/*.exs"], - subdirectories: ["apps/*"] -] diff --git a/.gitignore b/.gitignore index 2de045d..b38cee9 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,5 @@ erl_crash.dump # Temporary files, for example, from tests. /tmp/ +/.claude/dude/ +/.idea/ diff --git a/.mcp.json b/.mcp.json new file mode 100644 index 0000000..e916414 --- /dev/null +++ b/.mcp.json @@ -0,0 +1,8 @@ +{ + "mcpServers": { + "cupid0": { + "command": "npx", + "args": ["chrome-devtools-mcp@latest", "--autoConnect"] + } + } +} diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..fb83391 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,21 @@ +# cupid0 + +## FULL DESCRIPTIONS ONLY. PERIOD. + +When showing a job description, ALWAYS paste the FULL raw text — every word, no summarizing, no bullets, no "here's what it says". +If it's saved in /tmp/descriptions/, cat the whole file. +If it's not saved, fetch and paste everything. +NO EXCEPTIONS. NO SUMMARIES. NO REFORMATTING. + +## SHORTCUTS + +- desc: paste the entire file content, every word, no summarizing, no reformatting, no bullets + +## TAILORING RULES + +- Source: og_golden.md for style and impact bullets, ai_golden.md for AI/agentic work +- Keep og's precise impact format — no vibe fluff +- Where og doesn't cover what the job asks, pull from ai_golden but rewrite in og's style +- Only go back far enough in history to fill the role — no need to list everything +- Select and remix the best matching bullets, don't copy-paste everything +- Output is one tight resume that reads like og but speaks the job's language diff --git a/apps/bouncer/.formatter.exs b/apps/bouncer/.formatter.exs deleted file mode 100644 index d2cda26..0000000 --- a/apps/bouncer/.formatter.exs +++ /dev/null @@ -1,4 +0,0 @@ -# Used by "mix format" -[ - inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] -] diff --git a/apps/bouncer/.gitignore b/apps/bouncer/.gitignore deleted file mode 100644 index f8f1a9f..0000000 --- a/apps/bouncer/.gitignore +++ /dev/null @@ -1,26 +0,0 @@ -# The directory Mix will write compiled artifacts to. -/_build/ - -# If you run "mix test --cover", coverage assets end up here. -/cover/ - -# The directory Mix downloads your dependencies sources to. -/deps/ - -# Where third-party dependencies like ExDoc output generated docs. -/doc/ - -# Ignore .fetch files in case you like to edit your project deps locally. -/.fetch - -# If the VM crashes, it generates a dump, let's ignore it too. -erl_crash.dump - -# Also ignore archive artifacts (built via "mix archive.build"). -*.ez - -# Ignore package tarball (built via "mix hex.build"). -bouncer-*.tar - -# Temporary files, for example, from tests. -/tmp/ diff --git a/apps/bouncer/README.md b/apps/bouncer/README.md deleted file mode 100644 index d9a622e..0000000 --- a/apps/bouncer/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# Bouncer - -**TODO: Add description** - -## Installation - -If [available in Hex](https://hex.pm/docs/publish), the package can be installed -by adding `bouncer` to your list of dependencies in `mix.exs`: - -```elixir -def deps do - [ - {:bouncer, "~> 0.1.0"} - ] -end -``` - -Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) -and published on [HexDocs](https://hexdocs.pm). Once published, the docs can -be found at . - diff --git a/apps/bouncer/lib/bouncer.ex b/apps/bouncer/lib/bouncer.ex deleted file mode 100644 index 9935ccc..0000000 --- a/apps/bouncer/lib/bouncer.ex +++ /dev/null @@ -1,18 +0,0 @@ -defmodule Bouncer do - @moduledoc """ - Documentation for `Bouncer`. - """ - - @doc """ - Hello world. - - ## Examples - - iex> Bouncer.hello() - :world - - """ - def hello do - :world - end -end diff --git a/apps/bouncer/lib/bouncer/application.ex b/apps/bouncer/lib/bouncer/application.ex deleted file mode 100644 index fe8da9a..0000000 --- a/apps/bouncer/lib/bouncer/application.ex +++ /dev/null @@ -1,20 +0,0 @@ -defmodule Bouncer.Application do - # See https://hexdocs.pm/elixir/Application.html - # for more information on OTP Applications - @moduledoc false - - use Application - - @impl true - def start(_type, _args) do - children = [ - # Starts a worker by calling: Bouncer.Worker.start_link(arg) - # {Bouncer.Worker, arg} - ] - - # See https://hexdocs.pm/elixir/Supervisor.html - # for other strategies and supported options - opts = [strategy: :one_for_one, name: Bouncer.Supervisor] - Supervisor.start_link(children, opts) - end -end diff --git a/apps/bouncer/mix.exs b/apps/bouncer/mix.exs deleted file mode 100644 index 17c8f18..0000000 --- a/apps/bouncer/mix.exs +++ /dev/null @@ -1,35 +0,0 @@ -defmodule Bouncer.MixProject do - use Mix.Project - - def project do - [ - app: :bouncer, - version: "0.1.0", - build_path: "../../_build", - config_path: "../../config/config.exs", - deps_path: "../../deps", - lockfile: "../../mix.lock", - elixir: "~> 1.15", - start_permanent: Mix.env() == :prod, - deps: deps() - ] - end - - # Run "mix help compile.app" to learn about applications. - def application do - [ - extra_applications: [:logger], - mod: {Bouncer.Application, []} - ] - end - - # Run "mix help deps" to learn about dependencies. - defp deps do - [ - {:cabbage, "~> 0.4.0"}, - # {:dep_from_hexpm, "~> 0.3.0"}, - # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}, - # {:sibling_app_in_umbrella, in_umbrella: true} - ] - end -end diff --git a/apps/bouncer/test/bouncer_feature_test.exs b/apps/bouncer/test/bouncer_feature_test.exs deleted file mode 100644 index c96442c..0000000 --- a/apps/bouncer/test/bouncer_feature_test.exs +++ /dev/null @@ -1,16 +0,0 @@ -defmodule Bouncer.FeatureTest do - use Cabbage.Feature, file: "bouncer.feature" - use ExUnit.Case - - defgiven ~r/^I am at the door$/, _vars, _state do - {:ok, %{}} - end - - defwhen ~r/^the bouncer greets me$/, _vars, state do - {:ok, state} - end - - defthen ~r/^I should be asked for ID$/, _vars, _state do - assert true - end -end diff --git a/apps/bouncer/test/bouncer_test.exs b/apps/bouncer/test/bouncer_test.exs deleted file mode 100644 index 95192ec..0000000 --- a/apps/bouncer/test/bouncer_test.exs +++ /dev/null @@ -1,8 +0,0 @@ -defmodule BouncerTest do - use ExUnit.Case - doctest Bouncer - - test "greets the world" do - assert Bouncer.hello() == :world - end -end diff --git a/apps/bouncer/test/cabbage_test.exs b/apps/bouncer/test/cabbage_test.exs deleted file mode 100644 index 0d8951a..0000000 --- a/apps/bouncer/test/cabbage_test.exs +++ /dev/null @@ -1,8 +0,0 @@ -defmodule Bouncer.CabbageTest do - use ExUnit.Case - - test "cabbage is installed" do - # Just a dummy test to make sure cabbage is available - assert Code.ensure_loaded?(Cabbage) - end -end diff --git a/apps/bouncer/test/features/bouncer.feature b/apps/bouncer/test/features/bouncer.feature deleted file mode 100644 index a9f25e0..0000000 --- a/apps/bouncer/test/features/bouncer.feature +++ /dev/null @@ -1,7 +0,0 @@ -Feature: Bouncer - The bouncer checks IDs at the door - - Scenario: Bouncer asks for ID - Given I am at the door - When the bouncer greets me - Then I should be asked for ID diff --git a/apps/bouncer/test/test_helper.exs b/apps/bouncer/test/test_helper.exs deleted file mode 100644 index 869559e..0000000 --- a/apps/bouncer/test/test_helper.exs +++ /dev/null @@ -1 +0,0 @@ -ExUnit.start() diff --git a/config/config.exs b/config/config.exs deleted file mode 100644 index ab23e80..0000000 --- a/config/config.exs +++ /dev/null @@ -1,18 +0,0 @@ -# This file is responsible for configuring your umbrella -# and **all applications** and their dependencies with the -# help of the Config module. -# -# Note that all applications in your umbrella share the -# same configuration and dependencies, which is why they -# all use the same configuration file. If you want different -# configurations or dependencies per app, it is best to -# move said applications out of the umbrella. -import Config - -# Sample configuration: -# -# config :logger, :console, -# level: :info, -# format: "$date $time [$level] $metadata$message\n", -# metadata: [:user_id] -# diff --git a/mix.exs b/mix.exs deleted file mode 100644 index e5ad8d9..0000000 --- a/mix.exs +++ /dev/null @@ -1,21 +0,0 @@ -defmodule Cupid0.MixProject do - use Mix.Project - - def project do - [ - apps_path: "apps", - version: "0.1.0", - start_permanent: Mix.env() == :prod, - deps: deps() - ] - end - - # Dependencies listed here are available only for this - # project and cannot be accessed from applications inside - # the apps folder. - # - # Run "mix help deps" for examples and options. - defp deps do - [] - end -end diff --git a/mix.lock b/mix.lock deleted file mode 100644 index 62cfd32..0000000 --- a/mix.lock +++ /dev/null @@ -1,4 +0,0 @@ -%{ - "cabbage": {:hex, :cabbage, "0.4.1", "30532a49ae1feeaaf89370a75a1f1b1101a403fee463317486ba5e9433c2c63a", [:mix], [{:gherkin, "~> 2.0", [hex: :gherkin, repo: "hexpm", optional: false]}], "hexpm", "1913fa883494430bf0748590ec381d4bfde58d347e796b5f7d5485366921ec55"}, - "gherkin": {:hex, :gherkin, "2.0.0", "41ac44571b47973c9dae198ead9650fed5363d5d512e8f6cfa643bf465910378", [:mix], [], "hexpm", "9cf21905d025f2487c1abc16f7c4e239088634a390da95253fcf70a4a8935828"}, -} diff --git a/resume/golden/ai.md b/resume/golden/ai.md new file mode 100644 index 0000000..562a187 --- /dev/null +++ b/resume/golden/ai.md @@ -0,0 +1,37 @@ +# AI Resume + +## Agentic Engineering + +### Dude + +Agentic harness around Claude Code. Includes SLDC workflows as skills based on BDD/ATDD and other Agile practices. Turn Claude into a lean XP machine. + +### Coolban + +Personal Kanban to run teams of Agents. Uses github projects and Claude gha to delegate work to agents. Allows human in the loop to review each phase and adapt the board to the process. + +### Vibe Coding Fridays + +Ongoing show showcasing practices, tools and experiments all vibe coded live. Introduced workflows, skills, MCPs, agents, TCR, BDD, anything related to agentic engineering or to the development of agents. + +## Agents + +### Candidate Sourcing + +Helps recruiter find candidates that would be a good fit for a job opportunity. Keeps a ranked list of scored applications to similar opportunities. Then reranks accordingly the current position. + +### Job Genius + +Help recruiters during the process of creating a job posting. Creates description based on selected skills. Recommends possible interview questions. + +### Smith + +Workbench to develop UKG agents. It bridges Agile practices with AI Engineering. Allows to TDD agents, refactor JSON and runs evals via XUnit tests. + +### Benito + +First agent in the team to run in CI. Allows to split PR reviews into a team of agents with different skills. + +### Elita + +Agentic platform that allows writing agents in pure md and they run as OTP gen servers. Applies OO paradigms to agentic programming. diff --git a/resume/golden/og.md b/resume/golden/og.md new file mode 100644 index 0000000..f2e612a --- /dev/null +++ b/resume/golden/og.md @@ -0,0 +1,47 @@ + + +| Mike Suarez mike.suarez.dev@gmail.com | [msuarz.com](http://msuarz.com) [github.com/msuarz](http://github.com/msuarz) [linkedin.com/in/mike-suarez](http://linkedin.com/in/mike-suarez) | +| :---- | ----: | +| Full-stack innovator merging code, culture, and collaboration. From monolith lifts to microservices, I keep solutions lean and user-focused. | | + +| Skills | | +| ----- | :---- | +| Languages Frameworks DevOps Data Process ArchitectureLeadership | C\#, JavaScript, Elixir, Ruby, Python .NET Core, Nodejs, React, Angular, Ruby on Rails GCP, Openstack, Docker, Kubernetes, Chef, Terraform MSSQL, MongoDB, Kafka, RabbitMQ, Elasticsearch XP, Kanban, Scrum, Lean Startup DDD, Microservices, REST, Event Driven Team Leader, Agile Coach, Pair and Mob Programming, Frequent Presenter | + +| Work Experience | +| :---- | + +| UKG \- *Principal Software Engineer* | | 2020 – Present | +| :---- | ----- | ----: | +| Ultimate Software merged with Kronos into a gigantic juggernaut to conquer the HRMS space. I took the helm of the Application team within the Recruiting module. | | | +| Reduced cycle time from 23 to 6 days for a distributed team of 16 by utilizing Kanban techniques, such as limiting work in progress and swarming on aging tasks. Increased Indeed Apply success rate by 80% by fully rewriting the integration within a fixed 3-month schedule. Improved MongoDB performance by publishing domain entities as Fat Events through Kafka topics, resulting in a 10% boost in efficiency. Boosted customer resolution rate by 40% by creating RecOps, an automated solution that provides easy access to production data and APIs for all team members. Eliminated a 40-minute deployment cycle to seconds by migrating to .NET Core and deploying on Kubernetes. Established the Lab (operating 10 a.m. – 4 p.m.) to foster mob programming for tackling tough challenges while sustaining a continuous, effective pace. | | | + +| Ultimate Software \- *Tech Lead* | | 2014 – 2020 | +| :---- | ----- | ----: | +| Embraced DevOps by founding rCloud, a custom PaaS that took a ’90s monolith to the cloud and helped our enterprise grow from 300 to 1,000 developers. | | | +| Accelerated UltiPro delivery increasing builds per day from less than 2 to over 30 by automating the deployments with Chef on ESX and OpenStack. Raised the success rate from 65% to 97%, despite instability in critical dependencies, by using a combination of retries, timeouts, and circuit breakers. Increased the user base by 20% by designing HALO, the front-end Angular-based SPA that brought UX to a pure RESTful platform. Slashed deployment time from 45 minutes to 5 seconds with a queue-based pipeline featuring pre-provisioned environments. Achieved 1-day cycle time for business rules changes, enabling rapid updates by extracting the core domain into a microservice using an internal DSL. | | | + +| Ultimate Software \- *Senior Software Engineer* | | 2008 – 2014 | +| :---- | ----- | ----: | +| Joined the Ulti family in the midst of the Agile revolution. Drove DevOps, Kanban and BDD adoption, fostering a culture of growth and innovation. | | | +| Pioneered DevOps adoption in partnership with ThoughtWorks to develop Recruiting, boosting UltiPro's per-employee pricing by $5. Engineered Droolz, a RESTful API for JBoss Drools, empowering external DSL-driven business rules and setting the stage for Payroll extraction from the monolith. Refactored in one week the Map/Reduce bottleneck for hydrating domain entities by effective date, allowing MongoDB to serve as an Event Store. Participated in the inaugural Kanban conference, initiated its adoption in a team of 5, and scaled to 17 members, revolutionizing software development practices. Contributed to Gojko Adzic's book "Specification by Example", amplifying Ultimate Software's exposure and helping define the practice of BDD. | | | + +| Alienware \- *Software Engineer* | | 2004 – 2008 | +| :---- | ----- | ----: | +| Got abducted into the realm of machine assembly. Amped up processes, quality, and performance of software solutions geared toward elite hardware consumers. | | | +| Optimized Alienfactory provisioning via retries and parallel processing, reducing assembly time per machine by 25%. Introduced Agile by blending XP and Scrum, achieving immediate improvements in communication through daily standups and pair programming. Mastered TDD by mentoring peers at AlienLabs, fostering team spirit and reducing defects by 80% compared to manually tested projects. Led the reengineering of a legacy C++ account manager into C\#, launching both WinForms and ASP.NET clients in just four months. | | | + +| Open Source Projects | +| :---- | + +| Limadelic \- *Owner* | | 2008 – Present | +| :---- | ----- | ----: | +| Founded a GitHub organization hosting up to 28 projects with 8 collaborators over 15+ years. Below are some of the most notable examples: | | | +| **Raconteur:** Acceptance test framework for Visual Studio that converts natural language specifications into XUnit tests. My most polished project, showcased through multiple demos and a presentation at AgileConf. **Decaf**: JavaScript driver for Slim crafted in CoffeeScript. Slim is the protocol powering Fitness, the seminal acceptance testing framework by Uncle Bob, one of the original signatories of the Agile manifesto. **FluentSpec:** C\# mock framework that leverages a fluent DSL with BDD-style given/when/then syntax for expressive mocking beyond RhinoMocks and Moq. It powered team testing until NSubstitute rose to prominence. | | | + +| Education | +| :---- | + +| University Of Miami, FL \- *BS in Computer Science* | | 2000 – 2004 | +| :---- | ----- | ----: | + diff --git a/tcr.sh b/tcr.sh deleted file mode 100755 index 75560d1..0000000 --- a/tcr.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/bash - -# TCR (test && commit || revert) script -# Usage: tcr : [exact_file_count] -# Example: tcr add:user authentication -# For more than 2 files, pass exact count: tcr : - -if [ -z "$1" ]; then - echo "❌ Error: Commit message required in format verb:description" - echo "Example: tcr add:user authentication" - exit 1 -fi - -if [[ ! "$1" =~ ^[a-z]+:.+ ]]; then - echo "❌ Error: Message must be in format verb:description" - echo "Example: tcr add:user authentication" - exit 1 -fi - -# Check number of files changed (including new files) -TOTAL_CHANGED_FILES=$(git status -s | wc -l | tr -d ' ') - -# List changed files -echo "Files changed:" -echo "" -git status -s | sed 's|apps/[^/]*/|apps/|g' - -# Check if too many files changed -if [ $TOTAL_CHANGED_FILES -gt 2 ] && [ "$2" != "$TOTAL_CHANGED_FILES" ]; then - echo "❌ Error: Too many files changed ($TOTAL_CHANGED_FILES). Maximum allowed: 2" - echo "To continue, run: tcr $1 $TOTAL_CHANGED_FILES" - exit 1 -fi - -# Show warning if using file count parameter -if [ $TOTAL_CHANGED_FILES -gt 2 ] && [ "$2" = "$TOTAL_CHANGED_FILES" ]; then - echo "⚠️ Running with $TOTAL_CHANGED_FILES files (more than default limit of 2)" -fi - -# Running TCR -echo "" -echo "Running TCR..." -echo "" - -# Run the tests -if mix test; then - # If tests pass, commit and push all changes (quietly) - git add . - git commit -q -m "$1" - echo "✅ Tests passed - committed and pushed: $1" -else - # If tests fail, revert all changes - # git reset --hard - # git clean -fd - echo "❌ Tests failed - changes reverted" -fi