diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,12 @@
+# Changelog
+
+`git-cuk` uses [PVP Versioning][1].
+The changelog is available [on GitHub][2].
+
+0.0.0
+=====
+
+* Initially created.
+
+[1]: https://pvp.haskell.org
+[2]: https://github.com/siapbantu/git-cuk/releases
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,373 @@
+Mozilla Public License Version 2.0
+==================================
+
+1. Definitions
+--------------
+
+1.1. "Contributor"
+    means each individual or legal entity that creates, contributes to
+    the creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+    means the combination of the Contributions of others (if any) used
+    by a Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+    means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+    means Source Code Form to which the initial Contributor has attached
+    the notice in Exhibit A, the Executable Form of such Source Code
+    Form, and Modifications of such Source Code Form, in each case
+    including portions thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+    means
+
+    (a) that the initial Contributor has attached the notice described
+        in Exhibit B to the Covered Software; or
+
+    (b) that the Covered Software was made available under the terms of
+        version 1.1 or earlier of the License, but not also under the
+        terms of a Secondary License.
+
+1.6. "Executable Form"
+    means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+    means a work that combines Covered Software with other material, in
+    a separate file or files, that is not Covered Software.
+
+1.8. "License"
+    means this document.
+
+1.9. "Licensable"
+    means having the right to grant, to the maximum extent possible,
+    whether at the time of the initial grant or subsequently, any and
+    all of the rights conveyed by this License.
+
+1.10. "Modifications"
+    means any of the following:
+
+    (a) any file in Source Code Form that results from an addition to,
+        deletion from, or modification of the contents of Covered
+        Software; or
+
+    (b) any new file in Source Code Form that contains any Covered
+        Software.
+
+1.11. "Patent Claims" of a Contributor
+    means any patent claim(s), including without limitation, method,
+    process, and apparatus claims, in any patent Licensable by such
+    Contributor that would be infringed, but for the grant of the
+    License, by the making, using, selling, offering for sale, having
+    made, import, or transfer of either its Contributions or its
+    Contributor Version.
+
+1.12. "Secondary License"
+    means either the GNU General Public License, Version 2.0, the GNU
+    Lesser General Public License, Version 2.1, the GNU Affero General
+    Public License, Version 3.0, or any later versions of those
+    licenses.
+
+1.13. "Source Code Form"
+    means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+    means an individual or a legal entity exercising rights under this
+    License. For legal entities, "You" includes any entity that
+    controls, is controlled by, or is under common control with You. For
+    purposes of this definition, "control" means (a) the power, direct
+    or indirect, to cause the direction or management of such entity,
+    whether by contract or otherwise, or (b) ownership of more than
+    fifty percent (50%) of the outstanding shares or beneficial
+    ownership of such entity.
+
+2. License Grants and Conditions
+--------------------------------
+
+2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+(a) under intellectual property rights (other than patent or trademark)
+    Licensable by such Contributor to use, reproduce, make available,
+    modify, display, perform, distribute, and otherwise exploit its
+    Contributions, either on an unmodified basis, with Modifications, or
+    as part of a Larger Work; and
+
+(b) under Patent Claims of such Contributor to make, use, sell, offer
+    for sale, have made, import, and otherwise transfer either its
+    Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+(a) for any code that a Contributor has removed from Covered Software;
+    or
+
+(b) for infringements caused by: (i) Your and any other third party's
+    modifications of Covered Software, or (ii) the combination of its
+    Contributions with other software (except as part of its Contributor
+    Version); or
+
+(c) under Patent Claims infringed by Covered Software in the absence of
+    its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+3. Responsibilities
+-------------------
+
+3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+(a) such Covered Software must also be made available in Source Code
+    Form, as described in Section 3.1, and You must inform recipients of
+    the Executable Form how they can obtain a copy of such Source Code
+    Form by reasonable means in a timely manner, at a charge no more
+    than the cost of distribution to the recipient; and
+
+(b) You may distribute such Executable Form under the terms of this
+    License, or sublicense it under different terms, provided that the
+    license for the Executable Form does not attempt to limit or alter
+    the recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+---------------------------------------------------
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: (a) comply with
+the terms of this License to the maximum extent possible; and (b)
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+5. Termination
+--------------
+
+5.1. The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated (a) provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and (b) on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+************************************************************************
+*                                                                      *
+*  6. Disclaimer of Warranty                                           *
+*  -------------------------                                           *
+*                                                                      *
+*  Covered Software is provided under this License on an "as is"       *
+*  basis, without warranty of any kind, either expressed, implied, or  *
+*  statutory, including, without limitation, warranties that the       *
+*  Covered Software is free of defects, merchantable, fit for a        *
+*  particular purpose or non-infringing. The entire risk as to the     *
+*  quality and performance of the Covered Software is with You.        *
+*  Should any Covered Software prove defective in any respect, You     *
+*  (not any Contributor) assume the cost of any necessary servicing,   *
+*  repair, or correction. This disclaimer of warranty constitutes an   *
+*  essential part of this License. No use of any Covered Software is   *
+*  authorized under this License except under this disclaimer.         *
+*                                                                      *
+************************************************************************
+
+************************************************************************
+*                                                                      *
+*  7. Limitation of Liability                                          *
+*  --------------------------                                          *
+*                                                                      *
+*  Under no circumstances and under no legal theory, whether tort      *
+*  (including negligence), contract, or otherwise, shall any           *
+*  Contributor, or anyone who distributes Covered Software as          *
+*  permitted above, be liable to You for any direct, indirect,         *
+*  special, incidental, or consequential damages of any character      *
+*  including, without limitation, damages for lost profits, loss of    *
+*  goodwill, work stoppage, computer failure or malfunction, or any    *
+*  and all other commercial damages or losses, even if such party      *
+*  shall have been informed of the possibility of such damages. This   *
+*  limitation of liability shall not apply to liability for death or   *
+*  personal injury resulting from such party's negligence to the       *
+*  extent applicable law prohibits such limitation. Some               *
+*  jurisdictions do not allow the exclusion or limitation of           *
+*  incidental or consequential damages, so this exclusion and          *
+*  limitation may not apply to You.                                    *
+*                                                                      *
+************************************************************************
+
+8. Litigation
+-------------
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+9. Miscellaneous
+----------------
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+10. Versions of the License
+---------------------------
+
+10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+-------------------------------------------
+
+  This Source Code Form is subject to the terms of the Mozilla Public
+  License, v. 2.0. If a copy of the MPL was not distributed with this
+  file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+---------------------------------------------------------
+
+  This Source Code Form is "Incompatible With Secondary Licenses", as
+  defined by the Mozilla Public License, v. 2.0.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,17 @@
+# git-cuk
+
+[![Hackage](https://img.shields.io/hackage/v/git-cuk.svg)](https://hackage.haskell.org/package/git-cuk)
+[![MPL-2.0 license](https://img.shields.io/badge/license-MPL--2.0-blue.svg)](LICENSE)
+[![Stackage Lts](http://stackage.org/package/git-cuk/badge/lts)](http://stackage.org/lts/package/git-cuk)
+[![Stackage Nightly](http://stackage.org/package/git-cuk/badge/nightly)](http://stackage.org/nightly/package/git-cuk)
+[![Build status](https://secure.travis-ci.org/siapbantu/git-cuk.svg)](https://travis-ci.org/siapbantu/git-cuk)
+
+Haskell Git Helper Tool
+
+## Configure
+
+Specify your login:
+
+```
+git config --global user.login <your_login>
+```
diff --git a/app/Main.hs b/app/Main.hs
new file mode 100644
--- /dev/null
+++ b/app/Main.hs
@@ -0,0 +1,8 @@
+module Main (main) where
+
+import System.IO (hSetEncoding, stdout, utf8)
+
+import Cuk (cuk)
+
+main :: IO ()
+main = hSetEncoding stdout utf8 >> cuk
diff --git a/git-cuk.cabal b/git-cuk.cabal
new file mode 100644
--- /dev/null
+++ b/git-cuk.cabal
@@ -0,0 +1,104 @@
+cabal-version:       2.0
+name:                git-cuk
+version:             0.0.1
+synopsis:            Haskell Git Helper Tool
+description:         Haskell Git Helper Tool
+homepage:            https://github.com/siapbantu/git-cuk
+bug-reports:         https://github.com/siapbantu/git-cuk/issues
+license:             MPL-2.0
+license-file:        LICENSE
+author:              Siapbantu
+maintainer:          human@shitiomatic.email
+copyright:           2020 Siapbantu
+category:            Git, CLI Tool
+build-type:          Simple
+extra-doc-files:     README.md
+                   , CHANGELOG.md
+tested-with:         GHC == 8.6.3
+
+source-repository head
+  type:                git
+  location:            https://github.com/siapbantu/git-cuk.git
+
+library
+  hs-source-dirs:      src
+  exposed-modules:     Cuk
+                         Cuk.Cli
+                         Cuk.ColorTerminal
+                         Cuk.Git
+                         Cuk.Issue
+                         Cuk.Shell
+
+  autogen-modules:     Paths_git_cuk
+  other-modules:       Paths_git_cuk
+                       Prelude
+
+  build-depends:       base-noprelude ^>= 4.12.0.0
+                     , ansi-terminal >= 0.8
+                     , github ^>= 0.20
+                     , gitrev ^>= 1.3
+                     , optparse-applicative ^>= 0.14
+                     , process ^>= 1.6.3
+                     , relude ^>= 0.4
+                     , text ^>= 1.2.1.0
+
+  ghc-options:         -Wall
+                       -Wincomplete-uni-patterns
+                       -Wincomplete-record-updates
+                       -Wcompat
+                       -Widentities
+                       -Wredundant-constraints
+                       -fhide-source-paths
+                       -Wmissing-export-lists
+                       -Wpartial-fields
+
+  default-language:    Haskell2010
+  default-extensions:  ConstraintKinds
+                       DeriveGeneric
+                       GeneralizedNewtypeDeriving
+                       InstanceSigs
+                       KindSignatures
+                       LambdaCase
+                       OverloadedStrings
+                       RecordWildCards
+                       ScopedTypeVariables
+                       StandaloneDeriving
+                       TupleSections
+                       TypeApplications
+                       ViewPatterns
+
+executable cuk
+  hs-source-dirs:      app
+  main-is:             Main.hs
+
+  build-depends:       base ^>= 4.12.0.0
+                     , git-cuk
+                     , relude
+
+  ghc-options:         -Wall
+                       -threaded
+                       -rtsopts
+                       -with-rtsopts=-N
+                       -Wincomplete-uni-patterns
+                       -Wincomplete-record-updates
+                       -Wcompat
+                       -Widentities
+                       -Wredundant-constraints
+                       -fhide-source-paths
+                       -Wmissing-export-lists
+                       -Wpartial-fields
+
+  default-language:    Haskell2010
+  default-extensions:  ConstraintKinds
+                       DeriveGeneric
+                       GeneralizedNewtypeDeriving
+                       InstanceSigs
+                       KindSignatures
+                       LambdaCase
+                       OverloadedStrings
+                       RecordWildCards
+                       ScopedTypeVariables
+                       StandaloneDeriving
+                       TupleSections
+                       TypeApplications
+                       ViewPatterns
diff --git a/src/Cuk.hs b/src/Cuk.hs
new file mode 100644
--- /dev/null
+++ b/src/Cuk.hs
@@ -0,0 +1,5 @@
+module Cuk
+       ( module Cuk
+       ) where
+
+import Cuk.Cli as Cuk
diff --git a/src/Cuk/Cli.hs b/src/Cuk/Cli.hs
new file mode 100644
--- /dev/null
+++ b/src/Cuk/Cli.hs
@@ -0,0 +1,138 @@
+{-# LANGUAGE ApplicativeDo   #-}
+{-# LANGUAGE TemplateHaskell #-}
+
+-- | Command line interface for @cuk@ executable.
+
+module Cuk.Cli
+       ( cuk
+       ) where
+
+import Data.Version (showVersion)
+import Development.GitRev (gitCommitDate, gitDirty, gitHash)
+import Options.Applicative (Parser, ParserInfo, argument, auto, command, execParser, fullDesc, help,
+                            helper, info, infoOption, long, metavar, progDesc, short, strArgument,
+                            subparser, switch)
+
+import Cuk.ColorTerminal (arrow, blueCode, boldCode, redCode, resetCode)
+import Cuk.Git (runCommit, runCurrent, runFix, runFresh, runHop, runNew, runPush, runResolve,
+                runSync)
+import Cuk.Issue (runIssue)
+
+import qualified Data.Text as T
+import qualified Paths_git_cuk as Meta (version)
+
+
+cuk :: IO ()
+cuk = execParser cliParser >>= \case
+    Hop branchName -> runHop branchName
+    Fresh branchName -> runFresh branchName
+    New issueNum -> runNew issueNum
+    Issue issueNum -> runIssue issueNum
+    Commit message noIssue -> runCommit message noIssue
+    Fix -> runFix
+    Resolve branchName -> runResolve branchName
+    Push isForce -> runPush isForce
+    Sync -> runSync
+    Current -> runCurrent >>= flip whenJust (runIssue . Just)
+
+----------------------------------------------------------------------------
+-- Parsers
+----------------------------------------------------------------------------
+
+-- | Main parser of the app.
+cliParser :: ParserInfo CukCommand
+cliParser = info ( helper <*> versionP <*> cukP )
+    $ fullDesc <> progDesc "Haskell Git Helper Tool"
+
+-- | Commands for
+data CukCommand
+    = Hop (Maybe Text)
+    | Fresh (Maybe Text)
+    | New Int
+    | Issue (Maybe Int)
+    | Commit Text Bool
+    | Fix
+    | Resolve (Maybe Text)
+    | Push Bool
+    | Sync
+    | Current
+
+-- | Commands parser.
+cukP :: Parser CukCommand
+cukP = subparser
+    $ command "hop"     (info (helper <*> hopP)     $ progDesc "Switch to branch and sync it")
+   <> command "fresh"   (info (helper <*> freshP)   $ progDesc "Rebase current branch on remote one")
+   <> command "new"     (info (helper <*> newP)     $ progDesc "Create new branch from current one")
+   <> command "commit"  (info (helper <*> commitP)  $ progDesc "Commit all local changes and prepend issue number")
+   <> command "fix"     (info (helper <*> fixP)     $ progDesc "Ammend changes to the last commit and force push")
+   <> command "issue"   (info (helper <*> issueP)   $ progDesc "Show the information about the issue")
+   <> command "push"    (info (helper <*> pushP)    $ progDesc "Push the current branch")
+   <> command "sync"    (info (helper <*> syncP)    $ progDesc "Sync local branch with its remote")
+   <> command "resolve" (info (helper <*> resolveP) $ progDesc "Switch to master, sync and delete the branch")
+   <> command "current" (info (helper <*> currentP) $ progDesc "Show info about current branch and issue (if applicable)")
+
+hopP :: Parser CukCommand
+hopP = Hop <$> maybeBranchP
+
+freshP :: Parser CukCommand
+freshP = Fresh <$> maybeBranchP
+
+newP :: Parser CukCommand
+newP = New <$> issueNumP
+
+issueP :: Parser CukCommand
+issueP = Issue <$> optional issueNumP
+
+commitP :: Parser CukCommand
+commitP = do
+    msg <- strArgument (metavar "COMMIT_MESSAGE")
+    noIssue <- switch
+        $ long "no-issue"
+       <> short 'n'
+       <> help "Do not add [#ISSUE_NUMBER] prefix when specified"
+    pure $ Commit msg noIssue
+
+fixP :: Parser CukCommand
+fixP = pure Fix
+
+pushP :: Parser CukCommand
+pushP = Push <$> switch
+    ( long "force"
+   <> short 'f'
+   <> help "Force push"
+    )
+
+syncP :: Parser CukCommand
+syncP = pure Sync
+
+currentP :: Parser CukCommand
+currentP = pure Current
+
+resolveP :: Parser CukCommand
+resolveP = Resolve <$> maybeBranchP
+
+-- | Parse optional branch name as an argument.
+maybeBranchP :: Parser (Maybe Text)
+maybeBranchP = optional $ strArgument (metavar "BRANCH_NAME")
+
+-- | Parse issue number as an argument.
+issueNumP :: Parser Int
+issueNumP = argument auto $ metavar "ISSUE_NUMBER"
+
+-- | Show the version of the tool.
+versionP :: Parser (a -> a)
+versionP = infoOption cukVersion
+    $ long "version"
+   <> short 'v'
+   <> help "Show cuk's version"
+
+cukVersion :: String
+cukVersion = toString
+    $ T.intercalate "\n"
+    $ [sVersion, sHash, sDate] ++ [sDirty | $(gitDirty)]
+  where
+    blueBold txt = blueCode <> boldCode <> txt <> resetCode
+    sVersion = blueBold "Cuk " <> "v" <> toText (showVersion Meta.version)
+    sHash = arrow <> blueBold "Git revision: " <> $(gitHash)
+    sDate = arrow <> blueBold "Commit date:  " <> $(gitCommitDate)
+    sDirty = redCode <> "There are non-committed files." <> resetCode
diff --git a/src/Cuk/ColorTerminal.hs b/src/Cuk/ColorTerminal.hs
new file mode 100644
--- /dev/null
+++ b/src/Cuk/ColorTerminal.hs
@@ -0,0 +1,89 @@
+-- | This module contains functions for colorful printing into terminal.
+
+module Cuk.ColorTerminal
+       ( Color (..)
+       , putStrFlush
+       , beautyPrint
+       , boldCode
+       , blueCode
+       , bold
+       , boldText
+       , boldDefault
+       , greenCode
+       , italic
+       , redCode
+       , reset
+       , resetCode
+       , setColor
+       , successMessage
+       , warningMessage
+       , errorMessage
+       , infoMessage
+       , skipMessage
+
+       , arrow
+       ) where
+
+import System.Console.ANSI (Color (..), ColorIntensity (Vivid), ConsoleIntensity (BoldIntensity),
+                            ConsoleLayer (Foreground), SGR (..), setSGR, setSGRCode)
+import System.IO (hFlush)
+
+
+-- | Explicit flush ensures prompt messages are in the correct order on all systems.
+putStrFlush :: Text -> IO ()
+putStrFlush msg = do
+    putText msg
+    hFlush stdout
+
+setColor :: Color -> IO ()
+setColor color = setSGR [SetColor Foreground Vivid color]
+
+-- | Starts bold printing.
+bold :: IO ()
+bold = setSGR [SetConsoleIntensity BoldIntensity]
+
+italic :: IO ()
+italic = setSGR [SetItalicized True]
+
+-- | Resets all previous settings.
+reset :: IO ()
+reset = do
+    setSGR [Reset]
+    hFlush stdout
+
+-- | Takes list of formatting options, prints text using this format options.
+beautyPrint :: [IO ()] -> Text -> IO ()
+beautyPrint formats msg = do
+    sequence_ formats
+    putText msg
+    reset
+
+boldText :: Text -> IO ()
+boldText message = bold >> putStrFlush message >> reset
+
+boldDefault :: Text -> IO ()
+boldDefault message = boldText (" [" <> message <> "]")
+
+colorMessage :: Color -> Text -> IO ()
+colorMessage color message = do
+    setColor color
+    putTextLn $ "  " <> message
+    reset
+
+errorMessage, warningMessage, successMessage, infoMessage, skipMessage :: Text -> IO ()
+errorMessage   = colorMessage Red
+warningMessage = colorMessage Yellow
+successMessage = colorMessage Green
+infoMessage    = colorMessage Blue
+skipMessage    = colorMessage Cyan
+
+blueCode, greenCode, boldCode, redCode, resetCode :: Text
+redCode   = toText $ setSGRCode [SetColor Foreground Vivid Red]
+blueCode  = toText $ setSGRCode [SetColor Foreground Vivid Blue]
+greenCode  = toText $ setSGRCode [SetColor Foreground Vivid Green]
+boldCode  = toText $ setSGRCode [SetConsoleIntensity BoldIntensity]
+resetCode = toText $ setSGRCode [Reset]
+
+-- | Arrow symbol
+arrow :: Text
+arrow = " ➤ "
diff --git a/src/Cuk/Git.hs b/src/Cuk/Git.hs
new file mode 100644
--- /dev/null
+++ b/src/Cuk/Git.hs
@@ -0,0 +1,130 @@
+{-# LANGUAGE ViewPatterns #-}
+
+-- | Logic for CLI commands to make GitHub workflows easier.
+
+module Cuk.Git
+       ( runHop
+       , runFresh
+       , runNew
+       , runPush
+       , runResolve
+       , runCommit
+       , runFix
+       , runSync
+       , runCurrent
+       ) where
+
+import Data.Char (isAlphaNum, isDigit, isSpace)
+
+import Cuk.ColorTerminal (arrow, errorMessage, greenCode, resetCode)
+import Cuk.Issue (getIssueTitle, mkIssueId)
+import Cuk.Shell (($|))
+
+import qualified Data.Text as T
+
+
+-- | @cuk hop@ command.
+runHop :: Maybe Text -> IO ()
+runHop (nameOrMaster -> branch) = do
+    "git" ["checkout",  branch]
+    "git" ["pull", "--rebase", "--prune"]
+
+-- | @cuk fresh@ command.
+runFresh :: Maybe Text -> IO ()
+runFresh (nameOrMaster -> branch) = do
+    "git" ["fetch", "origin", branch]
+    "git" ["rebase", "origin/" <> branch]
+
+-- | @cuk new@ command.
+runNew :: Int -> IO ()
+runNew issueNum = do
+    login <- "git" $| ["config", "user.login"]
+    if login == ""
+        then errorMessage "user.login is not specified"
+        else do
+            let issueId = mkIssueId issueNum
+            issueTitle <- getIssueTitle issueId
+            let shortDesc = mkShortDesc issueTitle
+            let branchName = login <> "/" <> show issueNum <> "-" <> shortDesc
+            "git" ["checkout", "-b", branchName]
+  where
+    mkShortDesc :: Text -> Text
+    mkShortDesc =
+          T.intercalate "-"
+        . take 5
+        . words
+        . T.filter (\c -> isAlphaNum c || isDigit c || isSpace c)
+
+-- | @cuk commit@ command.
+runCommit :: Text -> Bool -> IO ()
+runCommit (T.strip -> msg) (not -> hasIssue)
+    | msg == "" = errorMessage "Commit message cannot be empty"
+    | otherwise = do
+        branch <- getCurrentBranch
+        let issueNum = issueFromBranch branch
+        "git" ["add", "."]
+        "git" ["commit", "-m", showMsg $ guard hasIssue *> issueNum]
+  where
+    showMsg :: Maybe Int -> Text
+    showMsg = \case
+       Nothing -> msg
+       Just n  ->
+           let issue = "#" <> show n
+           in "[" <> issue <> "] " <> msg <> "\n\nResolves " <> issue
+
+-- | @cuk fix@ command.
+runFix :: IO ()
+runFix = do
+    "git" ["add", "."]
+    "git" ["commit", "--amend", "--no-edit"]
+    runPush True
+
+-- | @cuk push@ command.
+runPush :: Bool -> IO ()
+runPush isForce = getCurrentBranch >>= \branch ->
+    "git" $ ["push", "--set-upstream", "origin", branch]
+         ++ ["--force" | isForce]
+
+-- | @cuk sync@ command.
+runSync :: IO ()
+runSync = getCurrentBranch >>= \branch -> "git" ["pull", "--rebase", "origin", branch]
+
+-- | @cuk resolve@ command.
+runResolve :: Maybe Text -> IO ()
+runResolve (nameOrMaster -> master)= do
+    curBranch <- getCurrentBranch
+    runHop $ Just master
+    when (curBranch /= master) $ "git" ["branch", "-D", curBranch]
+
+{- | Part of the @cuk current@ command. Prints the current branch and returns
+the current issue number if possible.
+-}
+runCurrent :: IO (Maybe Int)
+runCurrent = do
+    branchName <- getCurrentBranch
+    putTextLn $ arrow <> "Current branch: " <> greenCode <> branchName <> resetCode
+    pure $ issueFromBranch branchName
+
+----------------------------------------------------------------------------
+-- Internal helpers
+----------------------------------------------------------------------------
+
+nameOrMaster :: Maybe Text -> Text
+nameOrMaster = fromMaybe "master"
+
+-- | Get the name of the current branch.
+getCurrentBranch :: IO Text
+getCurrentBranch = "git" $| ["rev-parse", "--abbrev-ref", "HEAD"]
+
+{- | Extracts issue number from the branch in form like:
+@
+siapbantu/<n>-short-description
+@
+-}
+issueFromBranch :: Text -> Maybe Int
+issueFromBranch =
+      readMaybe
+    . toString
+    . T.takeWhile isDigit
+    . T.drop 1
+    . T.dropWhile (/= '/')
diff --git a/src/Cuk/Issue.hs b/src/Cuk/Issue.hs
new file mode 100644
--- /dev/null
+++ b/src/Cuk/Issue.hs
@@ -0,0 +1,60 @@
+module Cuk.Issue
+       ( runIssue
+
+         -- * Internal helpers
+       , mkIssueId
+       , getIssueTitle
+       ) where
+
+import GitHub (Error, Id, Issue (..), IssueState (..), getUrl, mkId)
+import GitHub.Data.Options (stateOpen)
+import GitHub.Endpoints.Issues (issue, issuesForRepo)
+
+import Cuk.ColorTerminal (arrow, blueCode, errorMessage, redCode, resetCode)
+
+import qualified Data.Text as T
+
+
+-- | Run the @issue@ command.
+runIssue :: Maybe Int -> IO ()
+runIssue = \case
+    Just num -> getIssue $ mkIssueId num
+    Nothing -> getAllIssues
+
+-- | Get the list of the opened issues for the current project.
+getAllIssues :: IO ()
+getAllIssues = issuesForRepo "siapbantu" "git-cuk" stateOpen >>= \case
+    Left err -> errorMessage $ show err
+    Right is -> for_ is (putTextLn . showIssueName blueCode)
+
+-- | Get the 'Issue' by given issue number.
+getIssue :: Id Issue -> IO ()
+getIssue num = fetchIssue num >>= \case
+    Left err -> errorMessage $ show err
+    Right is -> putTextLn $ showIssueFull is
+
+showIssueName :: Text -> Issue -> Text
+showIssueName colorCode Issue{..} =
+    arrow <> colorCode <> "[#" <> show @Text issueNumber <> "] " <> resetCode <> issueTitle
+
+showIssueFull :: Issue -> Text
+showIssueFull i@Issue{..} = T.intercalate "\n" $
+       showIssueName (statusToCode issueState) i
+     : [ "    URL: " <> getUrl url | Just url <- [issueHtmlUrl]]
+    ++ [ "    " <> desc | Just (T.strip -> desc) <- [issueBody], desc /= ""]
+  where
+    statusToCode :: IssueState -> Text
+    statusToCode = \case
+        StateOpen -> blueCode
+        StateClosed -> redCode
+
+mkIssueId :: Int -> Id Issue
+mkIssueId = mkId $ Proxy @Issue
+
+fetchIssue :: Id Issue -> IO (Either Error Issue)
+fetchIssue = issue "siapbantu" "git-cuk"
+
+getIssueTitle :: Id Issue -> IO Text
+getIssueTitle num = fetchIssue num >>= \case
+    Left err -> errorMessage (show err) >> exitFailure
+    Right Issue{..} -> pure issueTitle
diff --git a/src/Cuk/Shell.hs b/src/Cuk/Shell.hs
new file mode 100644
--- /dev/null
+++ b/src/Cuk/Shell.hs
@@ -0,0 +1,30 @@
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE TypeFamilies      #-}
+
+{- | This module contains neat utilities to be able to work with
+shell commands in generic and simple way using just strings.
+-}
+
+module Cuk.Shell
+       ( ($|)
+       ) where
+
+import System.Process (callCommand, readProcess, showCommandForUser)
+
+import qualified Data.Text as T
+
+
+-- | This is needed to be able to call commands by writing strings.
+instance (a ~ Text, b ~ ()) => IsString ([a] -> IO b) where
+    fromString :: String -> [Text] -> IO ()
+    fromString cmd args = do
+        let cmdStr = showCommandForUser cmd (map toString args)
+        putStrLn $ "⚙  " ++ cmdStr
+        callCommand cmdStr
+
+-- | Run shell command with given options and return stdout of executed command.
+infix 5 $|
+($|) :: FilePath -> [Text] -> IO Text
+cmd $| args = T.strip . toText <$> readProcess cmd (map toString args) ""
diff --git a/src/Prelude.hs b/src/Prelude.hs
new file mode 100644
--- /dev/null
+++ b/src/Prelude.hs
@@ -0,0 +1,7 @@
+-- | Uses [relude](https://hackage.haskell.org/package/relude) as default Prelude.
+
+module Prelude
+       ( module Relude
+       ) where
+
+import Relude
