{"id":16306386,"url":"https://github.com/yanick/taskwarrior-kusarigama","last_synced_at":"2025-07-10T07:04:39.747Z","repository":{"id":56840782,"uuid":"53275779","full_name":"yanick/Taskwarrior-Kusarigama","owner":"yanick","description":"plugin system for the Taskwarrior task manager","archived":false,"fork":false,"pushed_at":"2019-05-01T00:23:11.000Z","size":223,"stargazers_count":23,"open_issues_count":7,"forks_count":8,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-06-15T02:10:06.585Z","etag":null,"topics":["taskwarrior"],"latest_commit_sha":null,"homepage":"https://metacpan.org/release/Taskwarrior-Kusarigama","language":"Perl","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yanick.png","metadata":{"files":{"readme":"README.mkdn","changelog":"Changes","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-03-06T20:56:31.000Z","updated_at":"2024-09-03T20:25:50.000Z","dependencies_parsed_at":"2022-08-29T05:00:26.551Z","dependency_job_id":null,"html_url":"https://github.com/yanick/Taskwarrior-Kusarigama","commit_stats":null,"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"purl":"pkg:github/yanick/Taskwarrior-Kusarigama","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yanick%2FTaskwarrior-Kusarigama","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yanick%2FTaskwarrior-Kusarigama/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yanick%2FTaskwarrior-Kusarigama/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yanick%2FTaskwarrior-Kusarigama/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yanick","download_url":"https://codeload.github.com/yanick/Taskwarrior-Kusarigama/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yanick%2FTaskwarrior-Kusarigama/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264545017,"owners_count":23625387,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["taskwarrior"],"created_at":"2024-10-10T21:10:29.552Z","updated_at":"2025-07-10T07:04:39.730Z","avatar_url":"https://github.com/yanick.png","language":"Perl","funding_links":[],"categories":[],"sub_categories":[],"readme":"# NAME\n\nTaskwarrior::Kusarigama - plugin system for the Taskwarrior task manager\n\n# VERSION\n\nversion 0.12.0\n\n# SYNOPSIS\n\n```\n$ task-kusarigama add GitCommit Command::ButBefore Command::AndAfter\n\n$ task-kusarigama install\n\n# enjoy!\n```\n\n# DESCRIPTION\n\nThis module provides a plugin-based way to run hooks and custom\ncommands for the\ncli-based task manager [Taskwarrior](http://taskwarrior.org/).\n\n## Configuring Taskwarrior to use Taskwarrior::Kusarigama\n\n### Setting up the hooks\n\nTaskwarrior's main method of customization is via hooks\nthat are executed when the command is run, when it exits, and when\ntasks are modified or added. (see [https://taskwarrior.org/docs/hooks.html](https://taskwarrior.org/docs/hooks.html)\nfor the official documentation) `Taskwarrior::Kusarigama` leverages this\nhook system to allow the creation of custom behaviors and commands.\n\nFirst, you need to install hook scripts that will invoke `Taskwarrior::Kusarigama`\nwhen `task` is running. You can do that by either using the helper `task-kusarigama`:\n\n```\n$ task-kusarigama install\n```\n\nOr dropping manually hook scripts in the `~/.task/hooks` directory. The scripts\nshould look like\n\n```perl\n#!/usr/bin/env perl\n\n# script '~/.task/hooks/on-launch-kusarigama.pl'\n\nuse Taskwarrior::Kusarigama;\n\nTaskwarrior::Kusarigama-\u003enew( raw_args =\u003e \\@ARGV )\n    -\u003erun_event( 'launch' ); # change with 'add', 'modify', 'exit'\n                             # for the different scripts\n```\n\n### Setting which plugins to use\n\nThen you need to tell the system with plugins to use,\neither via `task-kusarigama`\n\n```\n$ task-kusarigama add Command::AndAfter\n```\n\nor directly via the Taskwarrior config command\n\n```\n$ task config  kusarigama.plugins  Command::AndAfter\n```\n\n### Configure the plugins\n\nThe last step is to configure the different plugins. Read their\ndocumentation to do it manually or, again, use `task-kusarigama`.\n\n```\n$ task-kusarigama install\n```\n\n## Writing plugins\n\nThe inner workings of the plugin system are fairly simple.\n\nThe list of plugins we want to be active lives in the taskwarrior\nconfiguration under the key \u003ckusarigama.plugins\u003e. E.g.,\n\n```\nkusarigama.plugins=Renew,Command::ButBefore,Command::AndAfter,+FishCurrent\n```\n\nPlugin names prefixed with a plus sign are left alone (minus the '+'),\nwhile the other ones get `Taskwarrior::Kusarigama::Plugin::` prefixed to\nthem.\n\nThe Taskwarrior::Kusarigama system itself is invoked via the\nscripts put in `~/.task/hooks` by `task-kusarigama`. The scripts\ndetect in which stage they are called (launch, exit, add or modified),\nand execute all plugins that consume the associated role (e.g.,\n[Taskwarrior::Kusarigama::Hook::OnLaunch](https://metacpan.org/pod/Taskwarrior::Kusarigama::Hook::OnLaunch)), in the order they have been\nconfigured.\n\nFor example, this plugin will runs on a four hook stages:\n\n```perl\npackage Taskwarrior::Kusarigama::Plugin::PrintStage;\n\nuse 5.10.0;\n\nuse strict;\nuse warnings;\n\nuse Moo;\n\nextends 'Taskwarrior::Kusarigama::Plugin';\n\nwith 'Taskwarrior::Kusarigama::Hook::OnLaunch',\n     'Taskwarrior::Kusarigama::Hook::OnAdd',\n     'Taskwarrior::Kusarigama::Hook::OnModify',\n     'Taskwarrior::Kusarigama::Hook::OnExit';\n\nsub on_launch { say \"launch stage: \", __PACKAGE__; }\nsub on_add    { say \"add stage: \",    __PACKAGE__; }\nsub on_modify { say \"modify stage: \", __PACKAGE__; }\nsub on_exit   { say \"exit stage: \",   __PACKAGE__; }\n\n1;\n```\n\n### The Fifth Column: Taskwarrior::Kusarigama::Hook::OnCommand\n\nKusarigama defines a fifth hook role,\n[Taskwarrior::Kusarigama::Hook::OnCommand](https://metacpan.org/pod/Taskwarrior::Kusarigama::Hook::OnCommand), to help creating\ncustom commands. This role does two things: when\n`task-kusarigama install` is run, it creates a dummy report\nsuch that Taskwarrior will accept `task my_custom_command` as a\nvalid invocation, and then it runs as part of the `launch`\nstage and will run the plugin code if the associated command was used.\n\n### Adding custom fields to tasks\n\nTaskwarrior allows the creation of _User-Defined Attributes_ (UDAs). Plugins\ncan implement a `custom_uda` attribute that holds a hashref of\nnew UDAs and their description. Those UDAs will then be fed to Taskwarrior's\nconfig via `task-kusarigama install`, and will thereafter be available like\nany other task field.\n\nFor example, [Taskwarrior::Kusarigama::Plugin::Renew](https://metacpan.org/pod/Taskwarrior::Kusarigama::Plugin::Renew) uses UDAs\nto identify tasks that should create a new, follow-up instance\nof themselves upon completion:\n\n```perl\npackage Taskwarrior::Kusarigama::Plugin::Renew;\n\nuse strict;\nuse warnings;\n\nuse Clone 'clone';\nuse List::AllUtils qw/ any /;\n\nuse Moo;\nuse MooseX::MungeHas;\n\nextends 'Taskwarrior::Kusarigama::Hook';\n\nwith 'Taskwarrior::Kusarigama::Hook::OnExit';\n\nuse experimental 'postderef';\n\nhas custom_uda =\u003e sub{ +{\n    renew =\u003e 'creates a follow-up task upon closing',\n    rdue  =\u003e 'next task due date',\n    rwait =\u003e 'next task wait period',\n} };\n\nsub on_exit {\n    my( $self, @tasks ) = @_;\n\n    return unless $self-\u003ecommand eq 'done';\n\n    my $renewed;\n\n    for my $task ( @tasks ) {\n        next unless any { $task-\u003e{$_} } qw/ renew rdue rwait /;\n        $renewed = 1;\n\n        my $new = clone($task);\n\n        delete $new-\u003e@{qw/ end modified entry status uuid /};\n\n        my $due = $new-\u003e{rdue};\n        $new-\u003e{due} = $self-\u003ecalc($due) if $due;\n\n        my $wait = $new-\u003e{rwait};\n        $wait =~ s/due/$due/;\n        $new-\u003e{wait} = $self-\u003ecalc($wait) if $wait;\n\n        $new-\u003e{status} = $wait ? 'waiting' : 'pending';\n\n        $self-\u003eimport_task($new);\n    }\n\n    $self .= 'created follow-up tasks' if $renewed;\n}\n\n1;\n```\n\n### Aborting the pipeline\n\nAny plugin can abort the taskwarrior process by simply `die`ing.\n\n```perl\nsub on_add {\n    my( $self, $task ) = @_;\n\n    die \"need jira ticket for work tasks\"\n        if $task-\u003e{project} eq 'work' and not $task-\u003e{jira};\n}\n```\n\n# SEE ALSO\n\n- [http://techblog.babyl.ca/entry/taskwarrior](http://techblog.babyl.ca/entry/taskwarrior)\n\n    the original blog entry\n\n# AUTHOR\n\nYanick Champoux \u003cyanick@cpan.org\u003e [![endorse](http://api.coderwall.com/yanick/endorsecount.png)](http://coderwall.com/yanick)\n\n# COPYRIGHT AND LICENSE\n\nThis software is copyright (c) 2019, 2018, 2017 by Yanick Champoux.\n\nThis is free software; you can redistribute it and/or modify it under\nthe same terms as the Perl 5 programming language system itself.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyanick%2Ftaskwarrior-kusarigama","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyanick%2Ftaskwarrior-kusarigama","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyanick%2Ftaskwarrior-kusarigama/lists"}