{"id":45153125,"url":"https://github.com/pendashteh/potato","last_synced_at":"2026-02-20T03:30:50.230Z","repository":{"id":79360525,"uuid":"164534369","full_name":"pendashteh/potato","owner":"pendashteh","description":"Extends bash with \"Toppings\", real-time hooks into command execution.","archived":false,"fork":false,"pushed_at":"2026-01-01T05:09:33.000Z","size":103,"stargazers_count":1,"open_issues_count":2,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-01-05T23:30:46.744Z","etag":null,"topics":["bash-scripting","bashrc","framework","hooks","modular","postcommand","precommand"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pendashteh.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"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":null,"dco":null,"cla":null}},"created_at":"2019-01-08T02:01:13.000Z","updated_at":"2026-01-01T05:09:37.000Z","dependencies_parsed_at":"2023-03-12T07:52:56.539Z","dependency_job_id":null,"html_url":"https://github.com/pendashteh/potato","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/pendashteh/potato","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pendashteh%2Fpotato","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pendashteh%2Fpotato/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pendashteh%2Fpotato/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pendashteh%2Fpotato/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pendashteh","download_url":"https://codeload.github.com/pendashteh/potato/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pendashteh%2Fpotato/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29640536,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-20T03:21:14.183Z","status":"ssl_error","status_checked_at":"2026-02-20T03:18:24.455Z","response_time":59,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["bash-scripting","bashrc","framework","hooks","modular","postcommand","precommand"],"created_at":"2026-02-20T03:30:50.095Z","updated_at":"2026-02-20T03:30:50.219Z","avatar_url":"https://github.com/pendashteh.png","language":"Shell","readme":"# 🥔 Potato - Bash Extension Framework\n\n**Potato** is a modular bash extension system that lets you add custom functionality to your shell through \"toppings\" - small, focused scripts that hook into bash at different execution points.\n\n## Quick Start\n\n```bash\n# Add potato to your PATH and source it in ~/.bashrc\nexport PATH=\"$PATH:/path/to/potato-dir\"\nsource potato__ startup\n```\n\n## What are Toppings?\n\nToppings are bash scripts that execute at specific lifecycle events in your shell. Think of them as plugins or hooks that extend bash functionality without cluttering your main configuration.\n\n### Topping Types\n\nPotato supports three types of toppings based on filename suffix:\n\n| Type | Suffix | When It Runs | Use Cases |\n|------|--------|--------------|-----------|\n| **Startup** | `.bashrc` | Once when shell starts | Custom prompts, environment setup, aliases |\n| **Pre-command** | `.precommand` | Before each command executes | Validation, warnings, command modification |\n| **Post-command** | `.postcommand` | After each command completes | Logging, notifications, cleanup, state updates |\n\n### How Toppings Work\n\n```\n┌─────────────────────────────────────────────────┐\n│  Shell Startup                                  │\n│  └─\u003e All *.bashrc toppings load                │\n└─────────────────────────────────────────────────┘\n          ↓\n┌─────────────────────────────────────────────────┐\n│  User types command: cd /tmp                    │\n└─────────────────────────────────────────────────┘\n          ↓\n┌─────────────────────────────────────────────────┐\n│  All *.precommand toppings execute              │\n│  (can inspect/modify/cancel command)            │\n└─────────────────────────────────────────────────┘\n          ↓\n┌─────────────────────────────────────────────────┐\n│  Command executes: cd /tmp                      │\n└─────────────────────────────────────────────────┘\n          ↓\n┌─────────────────────────────────────────────────┐\n│  All *.postcommand toppings execute             │\n│  (can react to command results)                 │\n└─────────────────────────────────────────────────┘\n```\n\n## Usage\n\n### List Enabled Toppings\n\n```bash\npotato__ list\n```\n\nOutput example:\n```\nEnabled toppings:\n  git-prompt.bashrc\n  command-logger.postcommand\n  rm-warning.precommand\n```\n\n### Enable a Topping\n\n```bash\npotato__ enable /path/to/topping-name.bashrc\npotato__ enable ./rm-warning.precommand\npotato__ enable ../command-log.postcommand\n```\n\nThe filename **must** follow the naming convention: `NAME.TYPE` where TYPE is one of:\n- `bashrc` - for startup hooks\n- `precommand` - for pre-execution hooks  \n- `postcommand` - for post-execution hooks\n\n### Disable a Topping\n\n```bash\npotato__ disable topping-name.bashrc\n```\n\n### Reload All Toppings\n\nAfter enabling/disabling toppings:\n```bash\nsource potato__ startup\n```\n\nOr restart your shell.\n\n## Writing Toppings\n\n### Example 1: Git Branch in Prompt (bashrc)\n\n**File:** `git-prompt.bashrc`\n\n```bash\n#!/usr/bin/env bash\n# git-prompt.bashrc - Shows current git branch in PS1\n\n__git_branch() {\n    git branch 2\u003e/dev/null | grep '^*' | sed 's/* //'\n}\n\n# Add git branch to prompt\nPS1='\\u@\\h:\\w$(__git_branch | sed \"s/./ (\u0026)/\")\\$ '\n```\n\n### Example 2: Dangerous Command Warning (precommand)\n\n**File:** `rm-warning.precommand`\n\n```bash\n#!/usr/bin/env bash\n# rm-warning.precommand - Warns before dangerous rm commands\n\n# Check if command starts with 'rm'\nif [[ \"$BASH_COMMAND\" =~ ^rm.*\\*.*$ ]]; then\n    echo \"⚠️  WARNING: You're about to rm with wildcards!\"\n    echo \"Command: $BASH_COMMAND\"\n    read -p \"Continue? (y/N): \" -n 1 -r\n    echo\n    if [[ ! $REPLY =~ ^[Yy]$ ]]; then\n        # Cancel the command\n        return 1\n    fi\nfi\n```\n\n### Example 3: Command Logger (postcommand)\n\n**File:** `command-logger.postcommand`\n\n```bash\n#!/usr/bin/env bash\n# command-logger.postcommand - Logs commands and execution time\n\nLOG_FILE=\"$HOME/.command_history.log\"\n\n# Log the command with timestamp\necho \"[$(date '+%Y-%m-%d %H:%M:%S')] $PWD: $BASH_COMMAND\" \u003e\u003e \"$LOG_FILE\"\n\n# Optional: Track command success/failure\nif [[ $? -eq 0 ]]; then\n    echo \"  ✓ Success\" \u003e\u003e \"$LOG_FILE\"\nelse\n    echo \"  ✗ Failed (exit code: $?)\" \u003e\u003e \"$LOG_FILE\"\nfi\n```\n\n### Example 4: Tmux Preview Pane (postcommand)\n\n**File:** `tmux-preview.postcommand`\n\n```bash\n#!/usr/bin/env bash\n# tmux-preview.postcommand - Auto-updates tmux preview pane\n\n[[ -z \"$TMUX\" ]] \u0026\u0026 return 0\n\n# Detect directory changes\nif [[ \"$PWD\" != \"${POTATO_PREV_PWD:-}\" ]]; then\n    export POTATO_PREV_PWD=\"$PWD\"\n    \n    # Create preview pane if needed\n    if [[ $(tmux list-panes | wc -l) -eq 1 ]]; then\n        tmux split-window -h -d \"cat\"\n    fi\n    \n    PREVIEW_PANE=$(tmux list-panes -F \"#{pane_id}\" | tail -1)\n    \n    # Show README or directory listing\n    if [[ -f \"README.md\" ]]; then\n        tmux respawn-pane -t \"$PREVIEW_PANE\" -k \"cat README.md; cat\"\n    else\n        tmux respawn-pane -t \"$PREVIEW_PANE\" -k \"ls -lah; cat\"\n    fi\nfi\n```\n\n## Available Variables in Toppings\n\n### All Topping Types\n- `$PWD` - Current directory\n- `$HOME` - User home directory\n- `$USER` - Username\n- All standard bash variables\n\n### Precommand \u0026 Postcommand Only\n- `$BASH_COMMAND` - The command about to execute (precommand) or just executed (postcommand)\n- `$?` - Exit code of last command (postcommand only)\n\n### Custom Variables\nYou can create persistent variables by exporting them:\n\n```bash\n# In a .bashrc topping\nexport POTATO_MY_VARIABLE=\"value\"\n\n# Access in .precommand or .postcommand\necho $POTATO_MY_VARIABLE\n```\n\n## Best Practices\n\n### 1. Keep Toppings Focused\nEach topping should do one thing well. Don't create a massive topping that does everything.\n\n❌ **Bad:** `everything.postcommand` (500 lines, does logging, git updates, notifications, etc.)  \n✅ **Good:** Separate toppings for each feature\n\n### 2. Handle Errors Gracefully\nAlways check if commands/tools exist before using them:\n\n```bash\nif command -v git \u0026\u003e/dev/null; then\n    # Use git\nfi\n```\n\n### 3. Use Return Codes Properly\n- Return 0 for success\n- Return 1 to cancel/fail (especially in precommand)\n- Don't exit (it will close your shell!)\n\n```bash\n# In precommand\nif [[ some_dangerous_condition ]]; then\n    echo \"Cancelling command\"\n    return 1  # ✓ Correct\n    # exit 1  # ✗ Wrong - closes shell!\nfi\n```\n\n### 4. Avoid Heavy Operations\nPostcommand toppings run after **every** command. Keep them fast!\n\n❌ **Bad:** Network calls, slow computations  \n✅ **Good:** Quick checks, simple logging\n\n### 5. Log for Debugging\nWhen developing toppings, use a log file:\n\n```bash\nLOG=\"/tmp/my-topping.log\"\necho \"Debug: something happened\" \u003e\u003e \"$LOG\"\n```\n\n### 6. Name Descriptively\nUse clear, descriptive names:\n- `git-prompt.bashrc` ✓\n- `warn-rm.precommand` ✓\n- `stuff.postcommand` ✗\n\n## Real-World Example: Complete Workflow\n\nLet's create a development environment setup:\n\n**1. dev-env.bashrc** - Set up environment\n```bash\n#!/usr/bin/env bash\nexport DEV_ROOT=\"$HOME/projects\"\nexport PATH=\"$PATH:$DEV_ROOT/bin\"\n\nalias proj='cd $DEV_ROOT'\n```\n\n**2. git-check.precommand** - Warn about committing to main\n```bash\n#!/usr/bin/env bash\nif [[ \"$BASH_COMMAND\" =~ ^git\\ commit ]]; then\n    branch=$(git branch 2\u003e/dev/null | grep '^*' | cut -d' ' -f2)\n    if [[ \"$branch\" == \"main\" || \"$branch\" == \"master\" ]]; then\n        echo \"⚠️  You're committing to $branch!\"\n        read -p \"Continue? (y/N): \" -n 1 -r\n        echo\n        [[ ! $REPLY =~ ^[Yy]$ ]] \u0026\u0026 return 1\n    fi\nfi\n```\n\n**3. project-tracker.postcommand** - Track time in projects\n```bash\n#!/usr/bin/env bash\nTRACK_FILE=\"$HOME/.project_time.log\"\n\nif [[ \"$PWD\" != \"${PREV_PROJECT_DIR:-}\" ]]; then\n    export PREV_PROJECT_DIR=\"$PWD\"\n    if [[ \"$PWD\" =~ ^$HOME/projects/ ]]; then\n        project=$(basename \"$PWD\")\n        echo \"[$(date '+%Y-%m-%d %H:%M:%S')] Entered: $project\" \u003e\u003e \"$TRACK_FILE\"\n    fi\nfi\n```\n\nEnable them all:\n```bash\npotato__ enable dev-env.bashrc\npotato__ enable git-check.precommand\npotato__ enable project-tracker.postcommand\nsource potato__ startup\n```\n\n## Troubleshooting\n\n### My topping isn't running\n\n1. **Check if it's enabled:**\n   ```bash\n   potato__ list\n   ```\n\n2. **Check the filename:** Must end with `.bashrc`, `.precommand`, or `.postcommand`\n\n3. **Reload potato:**\n   ```bash\n   source potato__ startup\n   ```\n\n4. **Add debug logging:**\n   ```bash\n   echo \"Topping executed at $(date)\" \u003e\u003e /tmp/debug.log\n   ```\n\n### My postcommand is too slow\n\nPostcommands run after every command. Profile them:\n```bash\ntime source /path/to/topping.postcommand\n```\n\nConsider:\n- Moving heavy work to background: `some_slow_task \u0026`\n- Caching results\n- Only running on specific commands\n\n### Variables aren't persisting\n\nExport them in a `.bashrc` topping:\n```bash\n# In startup.bashrc\nexport MY_VAR=\"value\"\n\n# Now accessible in all toppings\necho $MY_VAR\n```\n\n## Dependencies\n\nPotato requires:\n- **bash** (4.0+)\n- **undies** framework (must be in `$PATH`)\n\nOptional but recommended:\n- `bat` - Better file viewing\n- `tree` - Directory visualization\n- `jq` - JSON processing\n\n## Installation\n\n```bash\n# Clone the repository\ngit clone https://github.com/pendashteh/potato.git\ncd potato\n\n# Add to your ~/.bashrc\necho 'export PATH=\"$PATH:'$(pwd)'\"' \u003e\u003e ~/.bashrc\necho 'source potato__ startup' \u003e\u003e ~/.bashrc\n\n# Reload\nsource ~/.bashrc\n```\n\n## Contributing\n\nTo contribute a topping:\n\n1. Write your topping following the naming convention\n2. Test it thoroughly\n3. Add it to the `toppings/` directory\n4. Document what it does and any dependencies\n5. Submit a pull request\n\n## Advanced Topics\n\n### Topping Load Order\n\nToppings are loaded alphabetically within each type:\n1. All `.bashrc` toppings (alphabetically)\n2. `.precommand` toppings execute before each command (alphabetically)\n3. `.postcommand` toppings execute after each command (alphabetically)\n\nTo control order, use numeric prefixes:\n- `01-first.bashrc`\n- `02-second.bashrc`\n- `99-last.bashrc`\n\n### Conditional Toppings\n\nEnable toppings conditionally:\n\n```bash\n# In your .bashrc\nif [[ \"$HOSTNAME\" == \"work-laptop\" ]]; then\n    potato__ enable work-settings.bashrc\nfi\n```\n\n### Topping Communication\n\nToppings can communicate via exported variables:\n\n```bash\n# In early.postcommand\nexport POTATO_COMMAND_COUNT=$((POTATO_COMMAND_COUNT + 1))\n\n# In later.postcommand\nif [[ $POTATO_COMMAND_COUNT -gt 100 ]]; then\n    echo \"You've run 100 commands!\"\nfi\n```\n\n## License\n\nGPL-3.0 License\n\n## Credits\n\nCreated by [pendashteh](https://github.com/pendashteh)\n\n---\n\n**Note:** This is a complete rewrite of the original potato. The old version is available in the `old` branch.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpendashteh%2Fpotato","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpendashteh%2Fpotato","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpendashteh%2Fpotato/lists"}